2015-04-27 89 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的名字

相關問題