MethodSecurityInterceptor for multiple methods

java, spring-security

Solution

You can implement your own method security annotations based on Spring `@PreAuthorize("")` construction.

To fetch extra information about the method(beyond method argument values) to SpEL evaluation context you can implement your own MethodSecurityExpressionHandler

@Service
public class MySecurityExpressionHandler extends
    DefaultMethodSecurityExpressionHandler {

    @Override
    public StandardEvaluationContext createEvaluationContextInternal(
        Authentication auth, MethodInvocation mi) {

    StandardEvaluationContext evaluationContext = super
            .createEvaluationContextInternal(auth, mi);

    SomeMethodInfoData methodInfoData = mi.getMethod(). ...;

    evaluationContext.setVariable("someData", <value computed based on method info data>);
    }

    return evaluationContext;
} 

and register it in your `global-method-security` declaration

<security:global-method-security
        pre-post-annotations="enabled">
        <security:expression-handler
            ref="mySecurityExpressionHandler" />
    </security:global-method-security>

Now you can create custom security annotations(and extra process annotation data in MySecurityExpressionHandler if required)

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("#<someData>")
public @interface CustomSecurityAnnotation { ... }

for example you can create a custom annotation to check user roles without messing with strings:

@MyUserRoleCheck(MyAppRole.Admin)
public void someMethod()

Problem

I would like to secure my services layer using Spring Security. As explained in the documentation, I need to use a `MethodSecurityInterceptor` that will check if the method invocation is allowed. To decide if a service method invocation is allowed for a given user, affecting a required role to the invoked method (using `MethodSecurityMetadataSource`) is not enough for me since it also depends on the parameters passed to the method. As suggested in the documentation, I can write a custom `AccessDecisionVoter` and access the arguments though the secured object (`MethodInvocation` in this case). But, my authorization logic is different across the methods. For example, the arguments may be different between multiple methods and the authorization logic will also be different. I see two options: - I can use conditional logic in the `AccessDecisionVoter` to determine the invoked method and the authorization logic to use, but it seems to be an ugly solution. - I can define one `MethodSecurityInterceptor` per method to secure. According to the Spring documentation, a `MethodSecurityInterceptor` is used to secure many methods, so it makes me thinking there is another way. The same question exists for access decision after method invocation (using `AfterInvocationProvider`). What are the alternatives?

Original source

Related problems