Spring Security entity field level security

2020-05-28 00:22发布

I have a Spring MVC application which presents a view which shows all of the fields from a Customer entity such as name, address, phone number etc. The application has various roles such as ROLE_USER and ROLE_ADMIN. Users with ROLE_USER are only able to see the customer name where as users with ROLE_ADMIN can see all of the customer fields.

At the moment the way I have implemented this is with a Thymeleaf view which makes use of the SpringSecurityDialect to restrict access to certain fields based on the user's role:

<th:block sec:authorize="hasRole('ROLE_ADMIN')">
  <div th:text="${customer.phoneNumber}" />
</th:block>

Whilst this works absolutely fine it doesn't feel right and it's difficult to test. I would like to write tests against the controller which call the controller method with a principal that has different roles such as testViewCustomerAsRoleAdmin and testViewCustomerAsRoleUser. This isn't possible to verify as the controller returns a Customer to the view which is fully populated and has every field accessible via the getters.

What I'm after is some sort of field level security at the entity level where I can make use of the Spring Security annotations:

@PreAuthorize("hasRole('ROLE_ADMIN')")
public String getPhoneNumber()
{
  return phoneNumber;
}

It would be ideal if this could then raise an AccessDeniedException when trying to access the field if the principal is not authorized.

The Jersey project seems to have this sort of concept which is mentioned here, here and an example here. It does however seem to be limited to role based security rather than the full SpEL support offered with @PreAuthorize

Is there any way or implementing this sort of thing with Spring Security, I know the security context or SpEL evaluation context is not available in entities as they are not Spring managed. If not, is there any other approach which might allow me to achieve the same thing?

EDIT:

I don't know the Spring Security framework inside out but it seems like something that might be able to be done using Spring AOP in ApectJ mode to instrument methods of domain (entity) classes. It would then be a case of getting hold of the AccessDecisionManager and passing along the authentication (presumably obtained from the SecurityContextHolder) along with the contents of the annotation on the domain class methods (if present). Does anyone have experience with doing this sort of thing?

1条回答
该账号已被封号
2楼-- · 2020-05-28 00:26

I've managed to solve the problem using Spring AOP in AspectJ mode. The various Spring annotations such as @Transactional and @PreAuthorize will work on any non-Spring managed classes if you enable AspectJ mode and perform either compile time or load time weaving, there is a very good example here: https://github.com/spring-projects/spring-security/tree/4.0.1.RELEASE/samples/aspectj-jc

You need to make sure you have the spring-security-aspects dependency in your project (or plugin if you're using compile-time weaving) to enable weaving of @Secured annotations. Despite the comment in AnnotationSecurityAspect which describes the class as:

Concrete AspectJ aspect using Spring Security @Secured annotation for JDK 1.5+.

The class does actually weave the other Spring annotations including @PreAuthorize, @PreFilter, @PostAuthorize and @PostFilter.

查看更多
登录 后发表回答