Spring Boot + Spring Security + Hierarchical Roles

时间:2014-10-30 18:56:50

标签: spring spring-security spring-boot

我试图在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);
    }
}

更新:以下是根据您的建议更新的代码,但仍然无效。

5 个答案:

答案 0 :(得分:7)

我刚刚通过这些设置,所以一定会让你现在开始运行。这是交易:

您引入了此注释@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;
    }
    
  2.         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;
      }
      

      }

    2. 我将名称GlobalMethodSecurityConfig命名为这个新类,并将当前的GlobalMethodSecurityConfig类更改为WebSecurityConfig或其他内容,以反映它是Web层的安全设置。

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

      希望这有帮助。

答案 1 :(得分:3)

您需要在Web表达式选民上设置角色层次结构。类似的东西:

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

更新:您也可以尝试设置上面的表达式处理程序:

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

答案 2 :(得分: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以获取更多信息。特别注意:仍然必须在扩展GlobalMethodSecurityConfiguration的类中包含EnableGlobalMethodSecurity以确定设置。

答案 3 :(得分:2)

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

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

答案 4 :(得分:0)

启用方法级安全性(即@EnableGlobalMethodSecurity(prePostEnabled = true))以及在WebSecurityConfigurerAdapter上支持Hierarchical-role。

1.只需要在任何其他使用@Bean注释的类上分隔RoleHierarchy 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;
    }
}

希望它可以帮助你。

相关问题