Spring Security @Secured注释和用户权限

And*_*niy 2 java spring spring-mvc spring-security

这是关于第Spring4版(MVC +安全性).我已实现UserDetailsServiceImpl,其中内部loadUserByUsername方法用户被授予其权限.说它很简单:

public UserDetails loadUserByUsername(String username) {
    ...     
    Collection<GrantedAuthority> authorities = new ArrayList<>();

    authorities.add(new SimpleGrantedAuthority("ADMIN"));

    return new org.springframework.security.core.userdetails.User(username, password, enabled, true, true, true, authorities);
    ...
}
Run Code Online (Sandbox Code Playgroud)

我有安全控制器,我在其中注释带有@Secured注释的方法:

@Secured("ADMIN")
@RequestMapping(value = "/users", method = RequestMethod.GET)
public String users(Model model ...) { ... }
Run Code Online (Sandbox Code Playgroud)

正如您在内部所见,loadUserByUsername我明确地ADMIN向用户授予角色.但是当我尝试访问时,/users我得到了Access is denied异常:

2016-04-19 10:25:16,899 DEBUG(http-nio-8080-exec-9)[org.springframework.security.web.access.ExceptionTranslationFilter] - 访问被拒绝(用户不是匿名的); 委托给AccessDeniedHandler org.springframework.security.access.AccessDeniedException:在org.springframework.security.access.vote.AffirmativeBased的org.springframework.security.access.vote.AbstractAccessDecisionManager.checkAllowIfAllAbstainDecisions(AbstractAccessDecisionManager.java:70)中拒绝访问.在org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232)在org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java决定(AffirmativeBased.java:88): 64)在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)在org.springframework.aop.framework.CglibAopProxy $ DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)...

(没有@Secured注释一切正常).

那么,我在这里错过了什么?

cas*_*lin 10

我也遇到过这个问题。Spring Security 4 自动为任何角色添加前缀ROLE_。有关更多详细信息,请参阅Spring Security 3.x 到 4.x 迁移指南。

禁用ROLE_前缀

正如迁移指南中所建议的,以下内容BeanPostProcessor可用于禁用自动ROLE_前缀:

public class DefaultRolesPrefixPostProcessor implements BeanPostProcessor, 
                                                        PriorityOrdered {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {

        // Remove this if you are not using JSR-250
        if (bean instanceof Jsr250MethodSecurityMetadataSource) {
            ((Jsr250MethodSecurityMetadataSource) bean).setDefaultRolePrefix(null);
        }

        if (bean instanceof DefaultMethodSecurityExpressionHandler) {
            ((DefaultMethodSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
        }

        if (bean instanceof DefaultWebSecurityExpressionHandler) {
            ((DefaultWebSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
        }

        if (bean instanceof SecurityContextHolderAwareRequestFilter) {
            ((SecurityContextHolderAwareRequestFilter)bean).setRolePrefix("");
        }

        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        return bean;
    }

    @Override
    public int getOrder() {
        return PriorityOrdered.HIGHEST_PRECEDENCE;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将其定义为一个 bean:

@Bean
public static DefaultRolesPrefixPostProcessor defaultRolesPrefixPostProcessor() {
    return new DefaultRolesPrefixPostProcessor();
}
Run Code Online (Sandbox Code Playgroud)

检查机关

或者,您可以使用@PreAuthorize注释检查权限:

@PreAuthorize("hasAuthority('ADMIN')")
Run Code Online (Sandbox Code Playgroud)

确保prePostEnabled已启用:

@EnableGlobalMethodSecurity(prePostEnabled = true)
Run Code Online (Sandbox Code Playgroud)


And*_*niy 9

令人惊讶的是,问题在于角色名称.由于defaultRolePrefix设置为ROLE_(请参阅org.springframework.security.access.vote.RoleVoter类),所有角色的名称都应以ROLE_prefix 开头.换句话说,当我改变了

authorities.add(new SimpleGrantedAuthority("ADMIN")); 至

authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));

并@Secured("ADMIN")以@Secured("ROLE_ADMIN")-一切都变得很好.