首页 > 解决方案 > 如何修复我用于方法级别安全性的角色层次结构

问题描述

我正在一个大型(28 个不同大小的控制器)jsp 项目中的控制器功能上实现方法级安全性(@PreAuthorize("hasRole('ROLE_OD')"))。权限很复杂,但有些角色是分层的:

ROLE_ADMIN > ROLE_OD ROLE_OD > ROLE_PD ROLE_PD > 成员 ROLE_ADMIN > ROLE_BGC

目前,如果角色层次结构由一个级别(ROLE_ADMIN > ROLE_OD)组成,则它适用于多个级别(ROLE_ADMIN > ROLE_OD ROLE_OD > ROLE_PD),我不知道为什么。

我不知道这是否重要,但我已经自定义了 User 和 UserPrivilege 对象,以便我可以在控制器方法中验证用户仅限于访问他们的信息。所有这些都有效,我可以从每个方法中成功访问 @AuthenticationPrincipal User 用户参数。当访问被拒绝时,我还可以查看每个用户的grantedAuthorities 以验证他们应该具有访问权限。

我以前从未输入过问题,所以我不确定多少代码就足够了,或者太多了,但我会尽力为您提供帮助我所需的一切。

我用 2 天时间研究了所有能找到的文档,并尝试了 5 种不同的方式来设置项目。我现在拥有它的方式,它适用于使用@PreAuthorize 的一个级别,但不适用于@Secure,即使我为此启用它也是如此。我还注意到,如果我不在层次结构中按降序排列角色,那么它甚至不会编译。我尝试了上千种不同的语法。

@PreAuthorize("hasRole('ROLE_OD')")
@RequestMapping(value="/testAccess",method = RequestMethod.GET)
public void testAccess(@AuthenticationPrincipal User user) {
    System.out.println("user has access to this method!");
}

    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled=true)
    public class MethodLevelConfiguration extends GlobalMethodSecurityConfiguration {

    @Bean
    public RoleHierarchyImpl roleHierarchy(){
    RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
    roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_OD and ROLE_OD > ROLE_PD");
    return roleHierarchy;
    }

    @Bean
    public RoleVoter roleVoter() {
        return new RoleHierarchyVoter(roleHierarchy());
    }

    @Autowired
    private RoleHierarchy roleHierarchy;


    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {

    DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
    expressionHandler.setPermissionEvaluator(new PermissionEvaluatorImpl());
                expressionHandler.setRoleHierarchy(roleHierarchy);
    return expressionHandler;
    }

    }
    @Configuration
    // @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


        @Autowired
        private PasswordEncoder myPasswordEncoder;

        @Autowired
        private UserDetailsService userDetailsService;

        @Autowired
        private WebAuthenticationDetailsSourceImpl authenticationDetailsSource;

        @Bean
        public WebAuthenticationDetailsSourceImpl authenticationDetailsSource() {
            return new WebAuthenticationDetailsSourceImpl();
        }

        @Bean
        public PasswordEncoder myPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }


        @Bean
        public DaoAuthenticationProvider authProvider() {
            AuthenticationProviderImpl authProvider = new AuthenticationProviderImpl();
            authProvider.setUserDetailsService(userDetailsService);
            authProvider.setPasswordEncoder(myPasswordEncoder());
            return authProvider;
        }

        @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService).passwordEncoder(myPasswordEncoder);
        }


        @Override
        protected void configure(HttpSecurity http) throws Exception {

    [.antMatchers() here...]

            http.headers().frameOptions().sameOrigin();
        }

如果我以具有 ROLE_PD 或 ROLE_ADMIN 的用户身份登录,我会收到打印消息“用户有权访问此方法!”

如果我以具有 ROLE_OD 的用户身份登录,我会收到错误:.mmaExceptionHandlerExceptionResolver : Resolved [org.springframework.security.access.AccessDeniedException: Access is denied]

标签: jspspring-security

解决方案


您必须使用行分隔符分隔角色层次结构,请参阅Spring Security Reference

11.1.4 分层角色

[...]

角色层次结构的使用允许您配置哪些角色(或权限)应包括其他角色。Spring Security 的 RoleVoter 的扩展版本,RoleHierarchyVoter配置了RoleHierarchy,从中获取分配给用户的所有“可访问权限”。典型的配置可能如下所示:

<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
    <constructor-arg ref="roleHierarchy" />
</bean>
<bean id="roleHierarchy"
    class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
    <property name="hierarchy">
        <value>
            ROLE_ADMIN > ROLE_STAFF
            ROLE_STAFF > ROLE_USER
            ROLE_USER > ROLE_GUEST
        </value>
    </property>
</bean>

和源代码RoleHierarchyImpl

[...]

/**
 * Parse input and build the map for the roles reachable in one step: the higher role
 * will become a key that references a set of the reachable lower roles.
 */
private void buildRolesReachableInOneStepMap() {
    this.rolesReachableInOneStepMap = new HashMap<>();
    for (String line : this.roleHierarchyStringRepresentation.split("\n")) {

[...]


推荐阅读