Spring Boot + Spring Security + Hierarchical Roles

前端 未结 5 1811
甜味超标
甜味超标 2020-12-13 21:59

I\'m trying to setup hierarchical roles in my Spring Boot app without success. I\'ve done all that\'s been said in different places in the Internet. But with none of them ha

相关标签:
5条回答
  • 2020-12-13 22:28

    You need to set the role hierarchy on the web expression voter. Something like:

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

    Update: You could also try setting the the above expression handler like this:

    http
        .authorizeRequests()
        .expressionHandler(expressionHandler)
        ...
    
    0 讨论(0)
  • 2020-12-13 22:30

    You have to set the role hierarchy on the 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;
        }
    }
    

    Check Javadoc for @EnableGlobalMethodSecurity for further information. Especially notice: that EnableGlobalMethodSecurity still must be included on the class extending GlobalMethodSecurityConfiguration to determine the settings.

    0 讨论(0)
  • 2020-12-13 22:30

    We can clearly see setHierarchy method of RoleHierarchyImpl class. They are splitting it with "\n" for more than 2 hierarchy roles.

    @Bean
    public RoleHierarchyImpl roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_WRITER\n" +
                "ROLE_ADMIN > ROLE_EDITOR");
        return roleHierarchy;
    }
    
    0 讨论(0)
  • 2020-12-13 22:31

    To Enable Method Level Security( ie @EnableGlobalMethodSecurity(prePostEnabled = true)) along with supporting Hierarchical-role on WebSecurityConfigurerAdapter.

    1.Just need to seperate the RoleHierarchy on any other class annotated with @Bean
    2.Inject it using @Autowired on WebSecurityConfigurerAdapter. It is working flawlessly on my projects.

    Please have a look into my code.

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

    Hope It helps you.

    0 讨论(0)
  • 2020-12-13 22:36

    I just went thru these setup so will definitely get you up running now. Here is the deal:

    You brought in this annotation @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) but didn't show any code to use Pre/Post Authorize/Filter so I don't know if you actually need it.

    1. If you don't need that class/method level security/filtering then all you need to do is:

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

    and

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

    You don't have to override with your own accessDecisionManager if all you need is to introduce a role hierarchy.

    1. If you also need class/method level security, i.e. using PreAuthorize, PostAuthorize, PreFilter, PostFilter on your methods/classes then also create a @Configuration like this in your classpath (and remove the @EnableGlobalMethodSecurity annotation from your GlobalMethodSecurityConfig class):

      @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;
      }
      

      }

    I would give the name GlobalMethodSecurityConfig to this new class and change your current GlobalMethodSecurityConfig class to WebSecurityConfig or something to reflect that it's the security setting for the web tier.

    I define the RoleHierarchy bean in the webSecurityConfig and inject/use it in the globalMethodSecurityConfig, but you can do that any way you like, as long as you don't create 2 beans unnecessarily.

    Hope this helps.

    0 讨论(0)
提交回复
热议问题