2014-10-30 25 views
9

Sto cercando di impostare i ruoli gerarchici nella mia app Spring Boot senza successo. Ho fatto tutto ciò che è stato detto in diversi posti su Internet. Ma con nessuno di loro sono stato in grado di risolvere il problema.Spring Boot + Spring Security + Hierarchical Roles

Ecco il codice della classe SecurityConfig. Quando accedo all'app con un utente con ROLE_ADMIN, dovrebbe essere in grado di recuperare i dati da "/ users", ma attualmente ricevo un'eccezione di accesso negata. Se l'utente ha le credenziali ROLE_USER, funziona correttamente. Qualcuno può aiutarmi a capire cosa sta fallendo? Grazie in anticipo.

@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("https://stackoverflow.com/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); 
    } 
} 

Aggiornamento: Ecco il codice aggiornato con il tuo suggerimento, ma ancora non funziona.

risposta

3

È necessario impostare la gerarchia di ruoli sull'elettore di espressioni Web. Qualcosa di simile:

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

Aggiornamento: Si potrebbe anche provare a impostare il sopra gestore espressione in questo modo:

http 
    .authorizeRequests() 
    .expressionHandler(expressionHandler) 
    ... 
+0

Non funziona in questo modo. Ricevo ancora la stessa eccezione di Accesso negato – Mario

+0

@Mario Prova il mio aggiornamento. – holmis83

+0

L'ho già fatto ieri ... Non ho idea del perché non funzioni perché ho fatto tutto il possibile senza successo. – Mario

3

È necessario impostare la gerarchia ruolo sulla 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; 
    } 
} 

Verificare Javadoc for @EnableGlobalMethodSecurity per ulteriori informazioni. Nota in particolare: che EnableGlobalMethodSecurity deve ancora essere incluso nella classe che estende GlobalMethodSecurityConfiguration per determinare le impostazioni.

7

Sono appena passato attraverso queste impostazioni, quindi sicuramente ti farò funzionare subito. Ecco l'offerta:

Hai inserito questa annotazione @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) ma non hai mostrato alcun codice per utilizzare Pre/Post Autorizza/Filtro quindi non so se ne hai effettivamente bisogno.

  1. Se non è necessario che il livello di classe/metodo di protezione/filtering, allora tutto quello che dovete fare è:

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

e

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

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

È don' t necessario eseguire l'override con il proprio accessDecisionManager se tutto ciò che serve è introdurre una gerarchia di ruoli.

  1. Se è necessario anche sicurezza di livello classe/metodo, ad es.utilizzando PreAuthorize, PostAuthorize, PreFilter, PostFilter sui vostri metodi/classi poi anche creare un @Configuration come questo nel classpath (e rimuovere l'annotazione @EnableGlobalMethodSecurity dalla classe GlobalMethodSecurityConfig):

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

    }

darei la chiama GlobalMethodSecurityConfig in questa nuova classe e modifica la tua attuale classe GlobalMethodSecurityConfig in WebSecurityConfig o qualcosa che rifletta che si tratta dell'impostazione di sicurezza per il livello web.

Definisco il bean RoleHierarchy nel webSecurityConfig e lo inietto/lo utilizzo in globalMethodSecurityConfig, ma è possibile farlo in qualsiasi modo, a patto di non creare 2 bean inutilmente.

Spero che questo aiuti.

+0

Ciao, grazie per la tua risposta! Sfortunatamente, Spring non mi consente di rimuovere l'annotazione '@ EnableGlobalMethodSecurity' dalla mia classe' WebSecurityConfig' - Ottengo 'IllegalArgumentException: ServletContext è necessario per configurare la gestione del servlet di default'. Qualsiasi aiuto apprezzato – kiedysktos

+0

OK, ho trovato una soluzione. Sembra che il tuo consiglio al punto 2. non sia poi così bello visto che per me funziona in senso inverso. Vedere una risposta qui: http://stackoverflow.com/questions/43468285/springboot-method-based-hierarchical-roles-security-servletcontext-is-require/43473615#43473615 – kiedysktos

0

Abilitare sicurezza a livello di metodo (ad esempio @EnableGlobalMethodSecurity (prePostEnabled = true)) insieme al ruolo di Hierarchical su WebSecurityConfigurerAdapter.

1.Just bisogno di separare il RoleHierarchy su qualsiasi altra classe annotato con @Bean
2.Inject utilizzando @Autowired su WebSecurityConfigurerAdapter. Sta funzionando perfettamente sui miei progetti.

Si prega di dare un'occhiata al mio codice.

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

}

Spero che ti aiuta.