2015-02-24 17 views
1

不久前我有一個有趣的情況,它在Spring Security的AuthenticationManager中導致了一個無限循環(並最終導致堆棧溢出)。幾個月來,一切都按預期工作,但後來我決定將我的XML配置轉換爲純代碼配置。這是我在Java配置基本設置:在Spring Security 3.2.5中,在AuthenticationManager實現內部導致無限循環的是什麼?

@Configuration 
@EnableWebMvcSecurity 
@ComponentScan(basePackages = { "com.my.company" }) 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    // Disable default configuration 
    public SecurityConfig() { 
     super(true); 
    } 

    @Autowired 
    AuthenticationProviderImpl authenticationProvider; 

    @Autowired 
    MyAuthenticationEntryPoint customAuthenticationEntryPoint; 

    @Autowired 
    AuthenticationTokenProcessingFilter authenticationTokenProcessingFilter; 

    @Bean(name = "authenticationManager") 
    @Override 
    public AuthenticationManager authenticationManagerBean() throws Exception { 
     return super.authenticationManagerBean(); 
    } 

    @Override 
    public void configure(WebSecurity web) throws Exception { 

     // Ignore requests of resources in security 
     web.ignoring().antMatchers("/resources/**") 
     // Ignore requests to authentication 
       .and().ignoring().antMatchers("/auth/**"); 
    } 

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

     // Define main authentication filter 
     http.addFilterBefore(authenticationTokenProcessingFilter, 
       UsernamePasswordAuthenticationFilter.class) 

       // Request path authorization 
       .authorizeRequests() 
       .antMatchers("/api/**") 
       .access("isAuthenticated()") 

       // Authentication provider 
       .and() 
       .authenticationProvider(authenticationProvider) 

       // Security failure exception handling 
       .exceptionHandling() 
       .authenticationEntryPoint(customAuthenticationEntryPoint) 

       // Session Management 
       .and().sessionManagement() 
       .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 

       // Default security HTTP headers 
       .and().headers().xssProtection().frameOptions() 
       .cacheControl().contentTypeOptions(); 
    } 
} 

不過,我很快就發現了這個配置出現問題的原因我AuthenticationProviderImpl(它實現了Spring Security的AuthenticationProvider接口)。當實現的重寫authenticate方法拋出BadCredentialsException時,該類中完全相同的方法將被永久調用,直到堆棧溢出。好消息是,我通過簡單覆蓋configure(AuthenticationManagerBuilder builder)中的SecurityConfig並聲明我在那裏實現了AuthenticationProvider而不是在configure(HttpSecurity http)中修復了我的配置。這裏是固定的版本:

@Configuration 
@EnableWebMvcSecurity 
@ComponentScan(basePackages = { "com.my.company" }) 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    // Disable default configuration 
    public SecurityConfig() { 
     super(true); 
    } 

    @Autowired 
    AuthenticationProviderImpl authenticationProvider; 

    @Autowired 
    MyAuthenticationEntryPoint customAuthenticationEntryPoint; 

    @Autowired 
    AuthenticationTokenProcessingFilter authenticationTokenProcessingFilter; 

    @Bean(name = "authenticationManager") 
    @Override 
    public AuthenticationManager authenticationManagerBean() throws Exception { 
     return super.authenticationManagerBean(); 
    } 

    @Override 
    public void configure(AuthenticationManagerBuilder builder) { 
     // Configure the authentication manager WITH the authentication 
     // provider. Not overriding this method causes very bad things to 
     // happen. 
     builder.authenticationProvider(authenticationProvider); 
    } 

    @Override 
    public void configure(WebSecurity web) throws Exception { 

     // Ignore requests of resources in security 
     web.ignoring().antMatchers("/resources/**") 
     // Ignore requests to authentication 
       .and().ignoring().antMatchers("/auth/**"); 
    } 

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

     // Define main authentication filter 
     http.addFilterBefore(authenticationTokenProcessingFilter, 
       UsernamePasswordAuthenticationFilter.class) 

       // Request path authorization 
       .authorizeRequests() 
       .antMatchers("/api/**") 
       .access("isAuthenticated()") 
       .and() 

       // Security failure exception handling 
       .exceptionHandling() 
       .authenticationEntryPoint(customAuthenticationEntryPoint) 

       // Session Management 
       .and().sessionManagement() 
       .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 

       // Default security HTTP headers 
       .and().headers().xssProtection().frameOptions() 
       .cacheControl().contentTypeOptions(); 
    } 
} 

雖然我相信我的問題就解決了與固定的配置,我仍然不知道爲什麼申請被無限調用authenticate()異常時由我實施AuthenticationProvider拋出?我嘗試了一下並檢查Spring Security類,但是我沒有找到合適的答案。感謝您的專業知識!

+0

有人猜測,我會說你的班級沒有正確地將控制權傳遞給過濾器鏈中的下一個鏈接。我強調這只是純粹的猜測,但如果啓用Spring Security的調試模式,您可以深入瞭解發生了什麼。 – JamesENL 2015-02-24 02:00:54

+0

有趣。日誌記錄並沒有顯示太多,除了這種模式在第一次迭代後重復:'2015-02-24 11:15:27 DEBUG - 返回單身bean'authenticationManager'的緩存實例 2015-02-24 11:15 :27 DEBUG - 使用com.my.company.service.AuthenticationProviderImpl進行身份驗證的嘗試 – Dustin 2015-02-24 16:22:27

回答

1

幾周前我也轉載了這個行爲,see this thread on stackoverflow

處理這個問題時,我發現當AuthenticationManager內部遍歷它的關聯AuthenticationProviders列表時發生了循環,然後找到一個自定義提供程序並嘗試使用已找到的提供程序執行身份驗證。如果提供者通過調用authenticate()將認證委託回AuthenticationManager,那麼您正在循環中。我猜你的AuthenticationProviderImpl做了那樣的事情?

您在提供商java.util.ListAuthenticationManager事宜的順序。訂單由您的配置給出,例如通過做您最初試圖什麼:

// Authentication provider 
.and() 
.authenticationProvider(authenticationProvider) 

通過改變你的配置,影響連接到您的經理,這最終將解決您的代碼提供的內部管理列表。

+0

這非常合理。我查看了Spring Security代碼,看看你的意思。我現在正在考慮用'AuthenticationManagerBuilder'來定義我的'AuthenticationProvider'的實現並不會導致默認的'AuthenticationProvider'被添加到過濾器鏈中。因此,我猜他們只是將球傳給對方。通過在右邊的'configure'方法中定義我的實現,我只將一個提供者添加到過濾器鏈中,在這種情況下這是正確的。這正是我希望得到的答案。謝謝! – Dustin 2015-02-25 14:00:39

相關問題