MethodSecurityInterceptor for multiple methods

后端 未结 2 1317
独厮守ぢ
独厮守ぢ 2020-12-20 17:54

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

2条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-20 18:18

    I achieved that by implementing my own AccessDecisionManager that delegates access decisions to my special interface AccessDecisionStrategy:

    public interface AccessDecisionStrategy {
    
        void decide(Authentication authentication, MethodInvocation methodInvocation, ConfigAttribute configAttribute);
    
    }
    

    Each access decision strategy represents different way of making access decision.

    You can easily implement your own strategy (even in other language - for instance Scala):

    public class SomeStrategy implements AccessDecisionStrategy { ...
    

    As you can see, my AccessDecisionManager has a map of strategies. Strategy used by manager is based on annotation argument.

    public class MethodSecurityAccessDecisionManager implements AccessDecisionManager {
    
        private Map strategyMap;
    
        public MethodSecurityAccessDecisionManager(Map strategyMap) {
            this.strategyMap = strategyMap;
        }
    
        @Override
        public void decide(Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
            ConfigAttribute configAttribute = getSingleConfigAttribute(configAttributes);
            AccessDecisionStrategy accessDecisionStrategy = strategyMap.get(configAttribute.getAttribute());
            if (accessDecisionStrategy == null) {
                throw new IllegalStateException("AccessDecisionStrategy with name "
                        + configAttribute.getAttribute() + " was not found!");
            }
            try {
                accessDecisionStrategy.decide(authentication, (MethodInvocation) object, configAttribute);
            } catch (ClassCastException e) {
                throw new IllegalStateException();
            }
        }
    
        private ConfigAttribute getSingleConfigAttribute(Collection configAttributes) {
            if (configAttributes == null || configAttributes.size() != 1) {
                throw new IllegalStateException("Invalid config attribute configuration");
            }
            return configAttributes.iterator().next();
        }
    
        @Override
        public boolean supports(ConfigAttribute attribute) {
            return true;
        }
    
        @Override
        public boolean supports(Class clazz) {
            return clazz.equals(MethodInvocation.class);
        }
    }
    

    Now when I want to protect my method I put @Secured annotation with argument that is name of the strategy:

    @Secured("GetByOwner")
    FlightSpotting getFlightSpotting(Long id);
    

    You can implement and configure as many strategies as you want:

    
    
        
            
                
                    
                
    
                
                    
                
            
        
    
    
    

    To inject that access decision manager you type:

    
    
    

    I also implemented helper class to handle MethodInvocation arguments:

    import org.aopalliance.intercept.MethodInvocation;
    
    public class MethodInvocationExtractor {
    
        private MethodInvocation methodInvocation;
    
        public MethodInvocationExtractor(MethodInvocation methodInvocation) {
            this.methodInvocation = methodInvocation;
        }
    
        public ArgumentType getArg(int num) {
            try {
                Object[] arguments = methodInvocation.getArguments();
                return (ArgumentType) arguments[num];
            } catch (ClassCastException | ArrayIndexOutOfBoundsException e) {
                throw new IllegalStateException();
            }
        }
    
    }
    

    Now you can easily extract interesting arguments in the code of your strategy to make decision:

    Let's say I want to get argument number 0 that is of type Long:

    MethodInvocationExtractor extractor = new MethodInvocationExtractor<>(methodInvocation);
    Long id = extractor.getArg(0);
    

提交回复
热议问题