2015-04-27 11 views
5

Erstens, ich bin neu in Java Spring Framework. Also vergib mir, wenn ich nicht genug Informationen zur Verfügung stelle. Ich habe versucht, RoleHierarchy in meine App hinzuzufügen, aber es hat nicht funktioniert. Unten sind die Codes, die ich versucht habe.Spring Sicherheitsrollenhierarchie funktioniert nicht mit 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; 
    } 

} 

Und Ich habe eine UserDetailsServiceImpl implements UserDetailsService vorsehen, dass die principal, Authentication und GrantedAuthority

Schließlich habe ich einige APIs:

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

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

Das Problem ist jetzt, wenn ich als ROLE_STAFF anmelden, ROLE_DEVELOPER, ROLE_ADMIN, bekam ich folgende Ergebnis.

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

Wie Sie ROLE_STAFF und ROLE_DEVELOPER gut funktionieren sehen. Aber ich möchte ROLE_ADMIN als eine super Rolle von beiden und es hat nicht funktioniert.

FYI, ich bin mit feder Sicherheit 3.2.5.RELEASE

Antwort

13

Das Problem ist in der RoleHierachy, die wie folgt sein sollte:

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

keep setHierarchy() Aufruf wird die Einstellung vor

außer Kraft setzen
+0

Beachten Sie, dass die Verwendung von "und" optional ist. Für Spring "" ROLE_ADMIN> ROLE_STAFF und ROLE_ADMIN "entspricht" "ROLE_ADMIN> ROLE_STAFF ROLE_ADMIN". Ich bevorzuge Ihre Notation aber nur sagen – kiedysktos

+0

Das funktioniert auch, wenn es optionale Syntax verwendet. Es wäre schön, wenn es eine Art Syntax-Ausnahme auslösen würde, weil ich 'A> B> C' –

11

Jedes Mal, wenn ich eine Rollenhierarchie mit Spring Security und Java Config implementieren möchte, verwende ich den folgenden Ansatz:

  1. Wir haben in Zusammenhang RoleHierarchyImpl Bohne hinzufügen (Sie sehen, dass ich mehrere Rollen verwenden, um eine Hierarchie aufbauen):

    @Bean 
    public RoleHierarchyImpl roleHierarchy() { 
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl(); 
        roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_DBA ROLE_DBA > ROLE_USER "); 
        return roleHierarchy; 
    } 
    
  2. Dann brauchen wir Web-Ausdruck-Handler erstellen passieren erhalten Hierarchie es:

    private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() { 
        DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler(); 
        defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy()); 
        return defaultWebSecurityExpressionHandler; 
    } 
    
  3. Der letzte Schritt ist in expressionHandler http.authorizeRequests() hinzuzufügen:

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

Ergebnis: in diesem speziellen Beispiel versuchen wir /dba Abschnitt zu besuchen, nachdem wir Admin-Benutzer bei der Verwendung (ROLE_ADMIN) angemeldet haben.Bevor wir eine Hierarchie erstellt haben, hatten wir ein Ergebnis mit Zugriffsverweigerung, aber jetzt können wir diesen Abschnitt ohne Probleme besuchen.

+0

sehr nützlich war! Vielen Dank! –

-2

Ich benutze keine Spring RoleHierarchy - weil es für mich nicht funktioniert. Aber ussualy ich tun, wie folgt: Rollen Schnittstelle

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

Liste meiner Rollen (speichern in DB) definieren:

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

als grundlegende Rolle Klasse definieren Anonymous Rolle:

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

Authentifizierte Rolle definieren (gemeinsame Benutzerrolle):

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

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

Administrator Rolle definieren (an der Spitze der Entwicklung):

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

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

Optional - statische Factory-Klasse:

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

In meinem CustomUserDetailsService (die UserDetailsService implementiert) Ich Rolle wie diese verwenden:

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

In Controller:

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

Erlaubt Benutzer sowohl in als ROLE_AUTHENTICATED und ROLE_ADMINISTRATOR angemeldet.

0

die createExpressionHandler Methode außer Kraft setzen, so dass es einen konfigurierten globalen Ausdruck Handler

@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

Für mich gibt die Lösung für die Instanz von DefaultWebSecurityExpressionHandler richtigen Bohnen Namen hatte. Der Name sollte webSecurityExpressionHandler sein.

@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()) 
      ... 
} 
Verwandte Themen