【问题标题】:Spring Boot + Spring Security + Hierarchical RolesSpring Boot + Spring Security + 分层角色
【发布时间】:2014-12-26 23:28:07
【问题描述】:

我试图在我的 Spring Boot 应用程序中设置分层角色,但没有成功。我已经完成了互联网上不同地方所说的所有内容。但是没有一个我能够解决这个问题。

这是我的 SecurityConfig 类的代码。当我使用具有 ROLE_ADMIN 的用户登录应用程序时,它应该能够从“/users”检索数据,但目前我收到拒绝访问异常。如果用户拥有 ROLE_USER 凭据,则可以正常工作。 谁能帮我弄清楚是什么失败了? 提前致谢。

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SigpaUserDetailsService userDetailsService;

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

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

    @Bean 
    public DefaultWebSecurityExpressionHandler expressionHandler(){
        DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
        expressionHandler.setRoleHierarchy(roleHierarchy());
        return expressionHandler;
    }

    @Bean
    @SuppressWarnings(value = { "rawtypes" })
    public AffirmativeBased accessDecisionManager() {       
        List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
        WebExpressionVoter webExpressionVoter = new WebExpressionVoter();
        webExpressionVoter.setExpressionHandler(expressionHandler());
        decisionVoters.add(webExpressionVoter);
        decisionVoters.add(roleVoter());
        return new AffirmativeBased(decisionVoters);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .accessDecisionManager(accessDecisionManager())
            .expressionHandler(expressionHandler())
            .antMatchers("/users/**")
                .access("hasRole('ROLE_USER')")
            .anyRequest().authenticated();
        http
            .formLogin()
                .loginPage("/login").permitAll()
                .and()
            .logout()
                .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder registry)
            throws Exception {
        registry.userDetailsService(userDetailsService);
    }
}

更新:这是根据您的建议更新的代码,但仍然无法正常工作。

【问题讨论】:

    标签: spring spring-security spring-boot


    【解决方案1】:

    我刚刚完成了这些设置,所以现在肯定会让你开始运行。这是交易:

    您引入了此注释 @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true),但没有显示任何使用 Pre/Post Authorize/Filter 的代码,所以我不知道您是否真的需要它。

    1. 如果您不需要该类/方法级别的安全/过滤,那么您需要做的就是:

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

    和

            private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() {
                DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
                defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy());
                return defaultWebSecurityExpressionHandler;
            }
    
    http
            .authorizeRequests()
            .expressionHandler(webExpressionHandler())
    

    如果您只需要引入角色层次结构,则不必使用自己的 accessDecisionManager 覆盖。

    1. 如果您还需要类/方法级别的安全性,即在您的方法/类上使用PreAuthorize, PostAuthorize, PreFilter, PostFilter,那么还要在您的类路径中创建一个类似这样的@Configuration(并从您的 GlobalMethodSecurityConfig 类中删除@EnableGlobalMethodSecurity 注释):

      @Configuration
      @EnableGlobalMethodSecurity(prePostEnabled=true)
      public class AnyNameYouLike extends GlobalMethodSecurityConfiguration {
      
      @Resource
      private RoleHierarchy roleHierarchy;
      
      @Override
      protected MethodSecurityExpressionHandler createExpressionHandler() {
          DefaultMethodSecurityExpressionHandler expressionHandler = (DefaultMethodSecurityExpressionHandler) super.createExpressionHandler();
          expressionHandler.setRoleHierarchy(roleHierarchy);
          return expressionHandler;
      }
      

      }

    我会给这个新类命名为 GlobalMethodSecurityConfig 并将您当前的 GlobalMethodSecurityConfig 类更改为 WebSecurityConfig 或其他东西以反映它是 Web 层的安全设置。

    我在 webSecurityConfig 中定义 RoleHierarchy bean 并在 globalMethodSecurityConfig 中注入/使用它,但是您可以按照自己喜欢的方式进行操作,只要您不要不必要地创建 2 个 bean。

    希望这会有所帮助。

    【讨论】:

    • 您好,感谢您的回答!不幸的是,Spring 不允许我从 WebSecurityConfig 类中删除 @EnableGlobalMethodSecurity 注释 - 我得到 IllegalArgumentException: A ServletContext is required to configure default servlet handling。任何帮助表示赞赏
    • 好的,我找到了解决方案。看起来您在第 2 点中的建议并不是那么好,因为对我来说它反过来起作用。在此处查看答案:stackoverflow.com/questions/43468285/…
    • 我无法运行此代码。就像在您的示例中那样覆盖 GlobalMethodSecurityConfiguration 类时,我收到 methodSecurityInterceptor bean 的 A bean with that name has already been defined .. 错误。我做错了什么?
    【解决方案2】:

    您需要在网络表达投票者上设置角色层次结构。比如:

    DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
    expressionHandler.setRoleHierarchy(roleHierarchy);
    webExpressionVoter.setExpressionHandler(expressionHandler);
    

    更新:您也可以尝试像这样设置上述表达式处理程序:

    http
        .authorizeRequests()
        .expressionHandler(expressionHandler)
        ...
    

    【讨论】:

    • 这样不行。我仍然收到相同的拒绝访问异常
    • 我昨天已经这样做了......我不知道为什么不工作,因为我已经做了所有可能的事情但没有任何成功。
    • 在这个http. authorizeRequests().expressionHandler(expressionHandler)工作了几个小时后
    【解决方案3】:

    您必须在 MethodSecurityExpressionHandler 上设置角色层次结构:

    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public static class GlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
        @Autowired
        private RoleHierarchy roleHierarchy;
    
        @Override
        protected MethodSecurityExpressionHandler createExpressionHandler() {
            final DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
            handler.setRoleHierarchy(this.roleHierarchy);
            return handler;
        }
    }
    

    查看Javadoc for @EnableGlobalMethodSecurity 了解更多信息。特别注意:EnableGlobalMethodSecurity 仍然必须包含在扩展 GlobalMethodSecurityConfiguration 的类中才能确定设置。

    【讨论】:

      【解决方案4】:

      我们可以清楚地看到 RoleHierarchyImpl 类的 setHierarchy 方法。他们使用“\n”将其拆分为超过 2 个层次结构角色。

      @Bean
      public RoleHierarchyImpl roleHierarchy() {
          RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
          roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_WRITER\n" +
                  "ROLE_ADMIN > ROLE_EDITOR");
          return roleHierarchy;
      }
      

      【讨论】:

        【解决方案5】:

        启用方法级别安全性(即@EnableGlobalMethodSecurity(prePostEnabled = true))以及支持WebSecurityConfigurerAdapter上的分层角色。

        1.只需将 RoleHierarchy 与任何其他使用 @Bean 注释的类分开
        2.在 WebSecurityConfigurerAdapter 上使用@Autowired 注入它。 它在我的项目中完美运行。

        请查看我的代码。

        WeSecurityConfig.class

        @Configuration
        @EnableGlobalMethodSecurity(prePostEnabled = true)
        @EnableWebSecurity
        public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
            @Autowired
            private RoleHierarchy roleHierarchy;
        
            private SecurityExpressionHandler<FilterInvocation>    webExpressionHandler() {
                DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler     = new DefaultWebSecurityExpressionHandler();
                defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy);
                return defaultWebSecurityExpressionHandler;
            }
        
            @Override
            public void configure(WebSecurity web) throws Exception {
                super.configure(web);
                web.ignoring().antMatchers("/static/**");
            }
        
            @Override
            public void configure(HttpSecurity http) throws Exception {
                http.
                    authorizeRequests()
                    .expressionHandler(webExpressionHandler())
                    .antMatchers("/static/**","/bower_components/**","/").permitAll()
                    .antMatchers("/user/login","/user/login?error").anonymous()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin().loginPage("/user/login").passwordParameter("password").usernameParameter("username")
                    .defaultSuccessUrl("/")
                    .permitAll()
                    .and()
                    .logout().logoutUrl("/user/logout")
                    .logoutSuccessUrl("/user/login?logout")
                    .and().csrf();
        
            }
        
            @Override
            public void configure(AuthenticationManagerBuilder auth) throws Exception {
                auth.authenticationProvider(daoAuthenticationProvider());
            }
        
            public DaoAuthenticationProvider daoAuthenticationProvider(){
                final DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
                auth.setUserDetailsService(userDetailService);
                auth.setPasswordEncoder(passwordEncoder);
                return auth;
            }
        }
        

        BeanConfiguration.class

        @Configuration
        public class BeanConfiguration {
        
            @Bean
            public RoleHierarchy roleHierarchy() {
                RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
                /* tricks lies here */
                roleHierarchy.setHierarchy("ROLE_SUPREME > ROLE_ADMIN ROLE_ADMIN > ROLE_OPERATOR ROLE_OPERATOR > ROLE_GUEST");
                return roleHierarchy;
            }
        }
        

        希望对你有帮助。

        【讨论】:

          猜你喜欢
          • 2019-12-19
          • 2014-05-01
          • 1970-01-01
          • 2016-10-03
          • 2016-01-03
          • 2012-12-01
          • 2019-06-21
          • 2016-10-16
          • 2012-03-14
          相关资源
          最近更新 更多