【问题标题】:Spring Security @Secured annotation and User authoritiesSpring Security @Secured 注释和用户权限
【发布时间】:2016-08-11 05:27:32
【问题描述】:

这是关于Spring v.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);
    ...
}

还有一个安全控制器,里面有一个带有@Secured注解的注解方法:

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

正如您在 loadUserByUsername 方法中看到的那样,我明确地将 ADMIN 角色授予用户。 但是当我尝试访问 /users 时,我得到一个 Access is denied 异常:

2016-04-19 10:25:16,899 调试 (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.AffirmativeBased.decide(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.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 在 org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) ...

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

我在这里错过了什么?

【问题讨论】:

  • 不,它没有。如果不知道这个事实,就不可能找到提到的问题。
  • 嗨,我通过查看关闭投票队列(来自重复投票)发现了这个问题。看起来它适用。你同意吗? (我问这个是因为你不接受它是骗子,所以我不想太快关闭它,也许我错过了一些东西)。
  • 亲爱的@Tunaki,我想它已经展示给你了,因为 ndrone 已经将它与我的结合了。当我搜索我的问题时,我没有发现任何类似的东西。请注意,如果潜在的 OP 与我的情况相同,他不会对 ROLE_ 前缀一无所知。他会搜索为什么标准配置不能工作的问题。

标签: java spring spring-mvc spring-security


【解决方案1】:

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

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

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

和@Secured("ADMIN") 到@Secured("ROLE_ADMIN") - 一切都很好。

【讨论】:

  • 就像你说的那样,当你设置新角色扩展 WebSecurityConfigurerAdapter 时会发生这种情况。但是,如果您在自己的 UserDetails 实现中设置角色(通过 UserDetailsS​​ervice),则不会发生该问题。
【解决方案2】:

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

禁用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;
    }
}

然后将其定义为一个bean:

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

检查机构

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

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

确保prePostEnabled 已启用:

@EnableGlobalMethodSecurity(prePostEnabled = true)

【讨论】:

    猜你喜欢
    • 2021-09-27
    • 2015-05-30
    • 1970-01-01
    • 2015-09-20
    • 2014-03-09
    • 2016-05-25
    • 2011-12-16
    • 2023-03-09
    • 2022-08-09
    相关资源
    最近更新 更多