2015-04-27 65 views
5

首先,我是Java Spring Framework的新手。所以如果我没有提供足够的信息,请原谅我。我曾尝试将RoleHierarchy添加到我的应用程序中,但它不起作用。以下是我尝试过的代码。Spring Security Role Hierarchy无法使用Java Config


SecurityConfig.java

// These config is try to set up a user Role Hierarchy 
@Bean 
public RoleHierarchy roleHierarchy() { 
    System.out.println("arrive public RoleHierarchy roleHierarchy()"); 
    RoleHierarchyImpl r = new RoleHierarchyImpl(); 
    r.setHierarchy("ROLE_ADMIN > ROLE_STAFF"); 
    r.setHierarchy("ROLE_STAFF > ROLE_USER"); 
    r.setHierarchy("ROLE_DEVELOPER > ROLE_USER"); 
    r.setHierarchy("ROLE_USER > ROLE_GUEST"); 
    return r; 
} 

@Bean 
public AffirmativeBased defaultAccessDecisionManager(RoleHierarchy roleHierarchy){ 
    System.out.println("arrive public AffirmativeBased defaultAccessDecisionManager()"); 
    List<AccessDecisionVoter> decisionVoters = new ArrayList<>(); 

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

    decisionVoters.add(webExpressionVoter); 
    decisionVoters.add(roleHierarchyVoter(roleHierarchy)); 
    // return new AffirmativeBased(Arrays.asList((AccessDecisionVoter) webExpressionVoter)); 
    return new AffirmativeBased(decisionVoters); 
} 

@Bean 
public RoleHierarchyVoter roleHierarchyVoter(RoleHierarchy roleHierarchy) { 
    System.out.println("arrive public RoleHierarchyVoter roleHierarchyVoter"); 
    return new RoleHierarchyVoter(roleHierarchy); 
} 

@Override 
protected void configure(HttpSecurity http) throws Exception { 
    // skipping some codes 
    http 
    // skipping some codes 
    .accessDecisionManager(defaultAccessDecisionManager(roleHierarchy())) 
    // skipping some codes 
} 

MethodSecurityConfig.java

@Configuration 
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true) 
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { 

    @Inject 
    private SecurityConfig securityConfig; 

    @Override 
    protected AuthenticationManager authenticationManager() throws Exception { 
    return securityConfig.authenticationManagerBean(); 
    } 

    @Override 
    protected MethodSecurityExpressionHandler createExpressionHandler() { 
    System.out.println("arrive protected MethodSecurityExpressionHandler createExpressionHandler()"); 
    DefaultMethodSecurityExpressionHandler d = new DefaultMethodSecurityExpressionHandler(); 
    d.setRoleHierarchy(securityConfig.roleHierarchy()); 
    return d; 
    } 

} 

而且我有一个UserDetailsServiceImpl implements UserDetailsService提供了principalAuthenticationGrantedAuthority

最后,我有一些API:

@PreAuthorize("hasRole('ROLE_STAFF')") 
@RequestMapping(value = "/api/v1/contactUs", method = RequestMethod.GET) 

@PreAuthorize("hasRole('ROLE_DEVELOPER')") 
@RequestMapping(value = "/api/v1/system", method = RequestMethod.GET) 

现在的问题是,如果我登录为ROLE_STAFF,ROLE_DEVELOPER,ROLE_ADMIN,我得到了以下结果。

| API  | ROLE_STAFF | ROLE_DEVELOPER | ROLE_ADMIN | 
|-----------|------------|----------------|------------| 
| contactUs | 200  | 403   | 403  | 
| system | 403  | 200   | 403  | 

正如你可以看到ROLE_STAFFROLE_DEVELOPER的工作就好了。但我想ROLE_ADMIN作为两个超级角色,它没有工作。

仅供参考,我使用弹簧安全3.2.5.RELEASE

回答

13

的问题是在RoleHierachy,这应该是这样的:

@Bean 
public RoleHierarchy roleHierarchy() { 
    RoleHierarchyImpl r = new RoleHierarchyImpl(); 
    r.setHierarchy("ROLE_ADMIN > ROLE_STAFF and ROLE_ADMIN > ROLE_DEVELOPER and ROLE_STAFF > ROLE_USER and ROLE_DEVELOPER > ROLE_USER"); 
    return r; 
} 

保持通话setHierarchy()将覆盖该设置之前

+0

请注意,使用“和”是可选的。对于Spring“”ROLE_ADMIN> ROLE_STAFF和ROLE_ADMIN“相当于”“ROLE_ADMIN> ROLE_STAFF ROLE_ADMIN”。我更喜欢你的符号,但只是说 – kiedysktos

+0

即使它使用可选的语法,这实际上也是有效的。如果它抛出某种语法异常会很好,因为我有'A> B> C' –

11

每次我想用Spring Security和Java配置实现角色层次结构时,我使用以下方法:

  1. 我们必须添加一个RoleHierarchyImpl豆到上下文(你看,我用多个角色建立一个层次):

    @Bean 
    public RoleHierarchyImpl roleHierarchy() { 
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl(); 
        roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_DBA ROLE_DBA > ROLE_USER "); 
        return roleHierarchy; 
    } 
    
  2. 然后,我们需要创建网络表达处理器来传递得到的层次结构,以它:

    private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() { 
        DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler(); 
        defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy()); 
        return defaultWebSecurityExpressionHandler; 
    } 
    
  3. 的最后一步是到expressionHandler加入到http.authorizeRequests():

     @Override 
         protected void configure(HttpSecurity http) throws Exception { 
          http 
           .authorizeRequests() 
            .expressionHandler(webExpressionHandler()) 
            .antMatchers("/admin/**").access("(hasRole('ROLE_ADMIN') or hasRole('ROLE_DBA')) and isFullyAuthenticated()") 
            .antMatchers("/dba").access("hasRole('ROLE_DBA') and isFullyAuthenticated()") 
            .antMatchers("/dba/**").access("hasRole('ROLE_USER')") 
            .and() 
           .requiresChannel() 
            .antMatchers("/security/**").requiresSecure() 
            .anyRequest().requiresInsecure() 
            .and() 
           .formLogin() 
            .loginPage("/login") 
            .failureUrl("/login?auth=fail") 
            .usernameParameter("username") 
            .passwordParameter("password") 
            .defaultSuccessUrl("/admin") 
            .permitAll() 
            .and() 
           .logout() 
             .logoutUrl("/logout") 
             .deleteCookies("remember-me") 
             .invalidateHttpSession(true) 
             .logoutSuccessUrl("/index") 
             .permitAll() 
             .and() 
           .csrf() 
             .and() 
           .rememberMe().tokenValiditySeconds(1209600) 
             .and() 
           .exceptionHandling().accessDeniedPage("/403") 
             .and() 
           .anonymous().disable() 
           .addFilter(switchUserFilter()); 
         } 
    

结果:在我们试图访问/DBA部分我们已经在使用管理员用户(ROLE_ADMIN)登录后,这个特殊的例子。在我们创建层次结构之前,我们有一个拒绝访问的结果,但现在我们可以毫无问题地访问这个部分。

+0

非常有用!谢谢! –

-2

我不使用Spring RoleHierarchy - 因为它不适合我。 但Ussualy我这样做: 定义角色界面我的角色

public static interface Role { 
    String getName(); 
    List<String> getHierarchy(); 
} 

列表(在数据库存储):

public interface AuthStates { 
    // Spring security works fine only with ROLE_*** prefix 
    String ANONYMOUS = "ROLE_ANONYMOUS"; 
    String AUTHENTICATED = "ROLE_AUTHENTICATED"; 
    String ADMINISTRATOR = "ROLE_ADMINISTRATOR"; 
} 

定义为基本角色类匿名角色:

public static class Anonymous implements Role { 
    private final String name; 
    private final List<String> hierarchy = Lists.newArrayList(ANONYMOUS); 

    public Anonymous() { 
    this(ANONYMOUS); 
    } 

    protected Anonymous(String name) { 
    this.name = name; 
    } 

    @Override 
    public String getName() { 
    return name; 
    } 

    @Override 
    public List<String> getHierarchy() { 
    return hierarchy; 
    } 

    protected void addHierarchy(String name) { 
    hierarchy.add(name); 
    } 
} 

定义认证角色(普通用户角色):

public static class Authenticated extends Anonymous { 
    public Authenticated() { 
    this(AUTHENTICATED); 
    } 

    protected Authenticated(String name) { 
    super(name); 
    addHierarchy(AUTHENTICATED); 
    } 
} 

定义管理员角色(在进化的顶部):

public static class Administrator extends Authenticated { 
    public Administrator() { 
    this(ADMINISTRATOR); 
    } 

    protected Administrator(String name) { 
    super(name); 
    addHierarchy(ADMINISTRATOR); 
    } 
} 

可选 - 静态工厂类:

public static Role getRole(String authState) { 
    switch (authState) { 
    case ANONYMOUS: return new Anonymous(); 
    case AUTHENTICATED: return new Authenticated(); 
    case ADMINISTRATOR: return new Administrator(); 
    default: throw new IllegalArgumentException("Wrong auth state"); 
    } 
} 

在我CustomUserDetailsS​​ervice(实现的UserDetailsS​​ervice)我使用的角色是这样的:

private Collection<GrantedAuthority> createAuthority(User user) { 
    final List<GrantedAuthority> authorities = new ArrayList<>(); 
    AuthStates.Role userAuthState = AuthStates.getRole(user.getAuthState()); 
    for (String role : userAuthState.getHierarchy()) { 
    authorities.add(new SimpleGrantedAuthority(role)); 
    } 
    return authorities; 
} 

authorities

在控制器:

@PreAuthorize("hasRole('ROLE_AUTHENTICATED')") 

将允许用户登录为ROLE_AUTHENTICATED和ROLE_ADMINISTRATOR两者。所以它返回一个配置的全局式处理器

@Configuration 
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) 
    public class GlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration { 
     @Autowired 
     private RoleHierarchy roleHierarchy; 

     @Override 
     protected MethodSecurityExpressionHandler createExpressionHandler(){ 
      return methodSecurityExpressionHandler(); 
     } 

     private DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler(){ 
      DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); 
      expressionHandler.setRoleHierarchy(roleHierarchy); 
      return expressionHandler; 
     } 

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

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

     @Configuration 
     public static class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

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

重写createExpressionHandler方法。名称应该是webSecurityExpressionHandler

@Bean 
public RoleHierarchyImpl roleHierarchy() { 
    RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl(); 
    roleHierarchy.setHierarchy(Roles.getRoleHierarchy()); 
    return roleHierarchy; 
} 

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

@Override 
protected void configure(HttpSecurity http) throws Exception { 
    http.authorizeRequests() 
      .expressionHandler(webSecurityExpressionHandler()) 
      ... 
} 
0

对于我的DefaultWebSecurityExpressionHandler实例的溶液具有适度的bean的名字

相关问题