PreAuthorize doesn't work

后端 未结 2 1515
孤街浪徒
孤街浪徒 2021-02-06 12:07

I\'m writing a socket server (no web-application !) application and want to use method-based security to handle my ACL needs. i followed a small tutorial i found spring security

相关标签:
2条回答
  • 2021-02-06 12:33

    This configuration worked just as expected for me:

    <bean id="securityExpressionHandler"
        class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" /> 
    
    <bean id="preInvocationAdvice"
        class="org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice"
        p:expressionHandler-ref="securityExpressionHandler" />
    
    <util:list id="decisionVoters">
        <bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
        <bean class="org.springframework.security.access.vote.RoleVoter" />
        <bean class="org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter"
            c:pre-ref="preInvocationAdvice" />
    </util:list>
    
    <bean id="accessDecisionManager"
        class="org.springframework.security.access.vote.UnanimousBased"
        c:decisionVoters-ref="decisionVoters" />
    
    <sec:global-method-security
        authentication-manager-ref="authenticationManager"
        access-decision-manager-ref="accessDecisionManager"
        pre-post-annotations="enabled" />
    

    I got the log message:

    WARN  org.springframework.security.access.expression.DenyAllPermissionEvaluator - 
        Denying user jack permission 'CHANNEL_WRITE' on object Channel[ name=null ]
    

    And an exception:

    org.springframework.security.access.AccessDeniedException: Access is denied
    

    From a simple test:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:META-INF/spring/application-context.xml")
    public class SpringSecurityPrePostTest {
    
        @Autowired
        ChannelService channelService;
    
        @Test
        public void shouldSecureService() throws Exception {
            Authentication authentication = new UsernamePasswordAuthenticationToken("jack", "sparrow");
            SecurityContext securityContext = SecurityContextHolder.getContext();
            securityContext.setAuthentication(authentication);
    
            channelService.writeMessage(new Channel(), "test");
        }
    }
    

    One thing I did diffrent was to use interface on a service and JDK proxies instead of cglib:

    public interface ChannelService {
    
        void writeMessage(Channel channel, String message);
    }
    

    and:

    @Component
    public class ChannelServiceImpl implements ChannelService {
    
        private static final Logger LOG = LoggerFactory.getLogger(ChannelServiceImpl.class);
    
        @Override
        @PreAuthorize("isAuthenticated() and hasPermission(#channel, 'CHANNEL_WRITE')")
        public void writeMessage(Channel channel, String message) {
            LOG.info("Writing message {} to: {}" , message, channel);
        }
    
    }
    

    UPDATE1:


    With this simplified config I get the same result:

    <bean id="securityExpressionHandler"
        class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" /> 
    
    <sec:global-method-security
        authentication-manager-ref="authenticationManager"
        pre-post-annotations="enabled">
        <sec:expression-handler ref="securityExpressionHandler" />
    </sec:global-method-security>
    

    UPDATE2:


    The debug message from Edit4 indicates that channelService may not have bean proxied at all as it got classified as not eligible for auto-proxying. This qiestion answers similar problem - try not to use @Autowired or any other mechanism based on BeanPostProcessors to set up the beans involved in security checks (i.e. myPermissionEvaluator).


    UPDATE3:


    You cannot use secured resources (i.e. services) within beans responsible for security checks! This creates a dependency loop and is a error in Your configuration. You must use lover level access (i.e. DAO) to check permissions, anything that is not secured! Implementing security checks using secured resources is not what You want to do.

    If despite using not secured resources with @Autowired things don't work as expected, try using old-school XML confiuration style for all beans involved in security checks. Also remember that <context:component-scan /> is in fact a BeanDefinitionRegistryPostProcessor and introduces the scanned beans into the BeanFactory after all the ones declared in XML are already there.

    0 讨论(0)
  • 2021-02-06 12:49

    it works, make sure that you have <sec:global-method-security pre-post-annotations="enabled"/> in your spring servlet (ie where you may have your <mvc:annotation-driven/>)

    "sec" is from xmlns:sec="http://www.springframework.org/schema/security"

    0 讨论(0)
提交回复
热议问题