2013-10-14 104 views
11
我有一些問題讓我的應用程序中設置使用我使用使用的Servlet 3.0風格的初始化通過 @EnableGlobalMethodSecurity控制方法級別的註釋

與Java配置和Spring Security的安全方法註釋3.2

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { 

    public SecurityWebApplicationInitializer() { 
     super(MultiSecurityConfig.class); 
    } 
} 

我已經嘗試2種不同初始化AuthenticationManager的方法都有自己的問題。請注意,而不是使用@EnableGlobalMethodSecurity會導致服務器成功啓動並且所有表單安全性按預期執行。當我在控制器上添加@EnableGlobalMethodSecurity@PreAuthorize("hasRole('ROLE_USER')")註釋時,我的問題就出現了。

我正在嘗試獨立設置基於表單和api的安全性。基於方法的註釋只需要用於api安全。

一種配置如下。

@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled=true) 
public class MultiSecurityConfig { 

    @Configuration 
    @Order(1) 
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 
     protected void configure(HttpSecurity http) throws Exception { 
      http.antMatcher("/api/**").httpBasic(); 
     } 

     protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception { 
      auth.inMemoryAuthentication() 
       .withUser("user").password("password").roles("USER").and() 
       .withUser("admin").password("password").roles("USER", "ADMIN"); 
     } 
    } 

    @Configuration 
    public static class FormWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { 
     public void configure(WebSecurity web) throws Exception { 
      web.ignoring().antMatchers("/static/**","/status"); 
     } 

     protected void configure(HttpSecurity http) throws Exception { 
      http.authorizeRequests().anyRequest().hasRole("USER").and() 
       .formLogin().loginPage("/login").permitAll(); 
     } 

     protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception { 
      auth.inMemoryAuthentication() 
       .withUser("user").password("password").roles("USER").and() 
       .withUser("admin").password("password").roles("USER", "ADMIN"); 
     } 
    } 

} 

,因爲我真的只想驗證機制,但主要問題的單一註冊這是不理想的是,它會導致以下異常:

java.lang.IllegalArgumentException: Expecting to only find a single bean for type interface org.springframework.security.authentication.AuthenticationManager, but found [] 

據我所知@EnableGlobalMethodSecurity設立了自己的AuthenticationManager,所以我不確定問題在這裏。

第二種配置如下。

@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled=true) 
public class MultiSecurityConfig { 

    @Bean 
    protected AuthenticationManager authenticationManager() throws Exception { 
     return new AuthenticationManagerBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR) 
       .inMemoryAuthentication() 
        .withUser("user").password("password").roles("USER").and() 
        .withUser("admin").password("password").roles("USER", "ADMIN").and() 
        .and() 
       .build(); 
    } 

    @Configuration 
    @Order(1) 
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 
     @Override protected void configure(HttpSecurity http) throws Exception { 
      http.antMatcher("/api/**").httpBasic(); 
     } 
    } 

    @Configuration 
    public static class FormWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { 
     public void configure(WebSecurity web) throws Exception { 
      web.ignoring().antMatchers("/static/**","/status"); 
     } 

     protected void configure(HttpSecurity http) throws Exception { 
      http.authorizeRequests().anyRequest().hasRole("USER").and() 
       .formLogin().loginPage("/login").permitAll(); 
     } 
    } 

} 

這個配置其實成功但有一個例外

java.lang.IllegalArgumentException: A parent AuthenticationManager or a list of AuthenticationProviders is required 
at org.springframework.security.authentication.ProviderManager.checkState(ProviderManager.java:117) 
at org.springframework.security.authentication.ProviderManager.<init>(ProviderManager.java:106) 
at org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.performBuild(AuthenticationManagerBuilder.java:221) 

,當我測試我發現,安全不工作開始。

我已經看了幾天,甚至在潛入春季安全實現代碼後,我似乎無法找到我的配置有什麼問題。

我正在使用spring-security-3.2.0.RC1和spring-framework-3.2.3.RELEASE。

+0

你在哪裏/如何加載這個'MultiSecurityConfig'。這是由'ContextLoaderListener'加載的嗎?如果安全性不如你的'DispatcherServlet'處理你的'Controllers'那麼安全。 –

回答

12

當您在WebSecurityConfigurerAdapter上使用protected registerAuthentication方法時,它將身份驗證範圍設定爲WebSecurityConfigurerAdapter,因此EnableGlobalMethodSecurity找不到它。如果你考慮這個問題......這是有道理的,因爲該方法是受保護的。

您看到的錯誤實際上是一個調試語句(請注意該級別是DEBUG)。原因是Spring Security會嘗試幾種不同的方式來自動連接Global Method Security。具體EnableGlobalMethodSecurity會嘗試以下方法來嘗試並獲得AuthenticationManager

  • 如果擴展GlobalMethodSecurityConfiguration和覆蓋registerAuthentication它將使用中傳遞的AuthenticationManagerBuilder。這允許以與WebSecurityConfigurerAdapter相同的方式隔離AuthenticationManager
  • 嘗試從全局共享實例AuthenticationManagerBuilder構建,如果它失敗,它會記錄您所看到的錯誤消息(注意日誌還聲明「這是現在確定,我們將嘗試直接使用AuthenticationManager「)
  • 嘗試使用作爲bean公開的AuthenticationManager

爲您的代碼,你將是最好關閉使用類似以下內容:

@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled=true) 
public class MultiSecurityConfig { 
    // Since MultiSecurityConfig does not extend GlobalMethodSecurityConfiguration and 
    // define an AuthenticationManager, it will try using the globally defined 
    // AuthenticationManagerBuilder to create one 

    // The @Enable*Security annotations create a global AuthenticationManagerBuilder 
    // that can optionally be used for creating an AuthenticationManager that is shared 
    // The key to using it is to use the @Autowired annotation 
    @Autowired 
    public void registerSharedAuthentication(AuthenticationManagerBuilder auth) throws Exception { 
     auth 
      .inMemoryAuthentication() 
       .withUser("user").password("password").roles("USER").and() 
       .withUser("admin").password("password").roles("USER", "ADMIN"); 
    } 

    @Configuration 
    @Order(1) 
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 
     // Since we didn't specify an AuthenticationManager for this class, 
     // the global instance is used 


     protected void configure(HttpSecurity http) throws Exception { 
      http 
       .antMatcher("/api/**") 
       .httpBasic(); 
     } 
    } 

    @Configuration 
    public static class FormWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { 
     // Since we didn't specify an AuthenticationManager for this class, 
     // the global instance is used 

     public void configure(WebSecurity web) throws Exception { 
      web 
       .ignoring() 
        .antMatchers("/static/**","/status"); 
     } 

     protected void configure(HttpSecurity http) throws Exception { 
      http 
       .authorizeRequests() 
        .anyRequest().hasRole("USER") 
        .and() 
       .formLogin() 
        .loginPage("/login") 
        .permitAll(); 
     } 
    } 

} 

注意:解決此更多的文檔將被添加到該在未來幾天的參考。

+0

感謝羅布,看起來像我的大部分問題歸結於我在使用代碼配置時對範圍的理解(或誤解)。這使事情變得更清晰。 – Luke

+1

後續問題 - 方法級別的安全性仍然不會觸發此配置。我註釋了我的類以要求ADMIN角色,但是經過身份驗證的USER成功執行該方法。這讓我認爲在授權不正確的情況下認證正常工作。有什麼想法嗎? – Luke

+0

我剛剛通過在此配置中創建bean來加載類,它識別並執行所有註釋。我清楚地使用代碼配置學習了一些關於上下文和範圍的知識! – Luke