java Spring Security @Secured 注解和用户权限

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36711538/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 01:47:57  来源:igfitidea点击:

Spring Security @Secured annotation and User authorities

javaspringspring-mvcspring-security

提问by Andremoniy

This is about Springv.4 (MVC + Security). I have implemented UserDetailsServiceImpl, where inside loadUserByUsernamemethod user is granted with its authorities. Say it's simply:

这大约是Springv.4(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);
    ...
}

And I have security controller inside which I've annotated method with @Securedannotation:

我有一个安全控制器,我在其中用@Secured注释注释了方法:

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

As you can see inside loadUserByUsernameI explicitly grant ADMINrole to user. But when I'm trying access to /usersI get Access is deniedexception:

正如你在里面看到的,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] - Access is denied (user is not anonymous); delegating to AccessDeniedHandler org.springframework.security.access.AccessDeniedException: Access is denied at org.springframework.security.access.vote.AbstractAccessDecisionManager.checkAllowIfAllAbstainDecisions(AbstractAccessDecisionManager.java:70) at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:88) at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232) at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:64) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) ...

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.AbstractAccessDecisionManager.checkAllowIfAllAbstainDecisions(AbstractAccessDecisionManager.java:70) 在 org.springframework.security.access.vote.Affirm决定(AffirmativeBased.java:88)在 org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232)在 org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java: 64) 在 org.springframework.aop.framework。

(without @Securedannotation everything works fine).

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

So, what have I missed here?

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

回答by Andremoniy

Surprisingly, but the problem was with roles names. Due to defaultRolePrefixset to ROLE_(see org.springframework.security.access.vote.RoleVoterclass) all roles should have names starting with ROLE_prefix. In other words, when I've changed

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

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

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

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

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

and @Secured("ADMIN")to @Secured("ROLE_ADMIN")- everything became fine.

@Secured("ADMIN")@Secured("ROLE_ADMIN")-一切都变得很好。

回答by cassiomolin

I also faced this issue. Spring Security 4 automatically prefixes any role with ROLE_. Refer to the Spring Security 3.x to 4.x migration guidefor more details.

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

Disabling ROLE_prefixing

禁用ROLE_前缀

As suggested in the migration guide, the following BeanPostProcessorcan be used to disable the automatic ROLE_prefixing:

正如迁移指南中所建议的,以下内容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;
    }
}

Then define it as a bean:

然后将其定义为bean:

@Bean
public static DefaultRolesPrefixPostProcessor defaultRolesPrefixPostProcessor() {
    return new DefaultRolesPrefixPostProcessor();
}

Checking authorities

检查机关

Alternatively you can check the authorities using the @PreAuthorizeannotation:

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

@PreAuthorize("hasAuthority('ADMIN')")

Ensure that prePostEnabledis enabled:

确保prePostEnabled已启用:

@EnableGlobalMethodSecurity(prePostEnabled = true)