2017-09-15 70 views
1

我有一個使用自定義身份驗證篩選器的spring應用程序說filter1來授權請求​​,此篩選器使用身份驗證管理器進行身份驗證,並適用於應用程序中的所有URL。多彈簧安全定製身份驗證

現在,我想實現一個不同的身份驗證過濾器說filter2必須授權特殊類型的請求說與url(/ api /)。這就是所有具有url(/ api/**)的請求必須使用filter2。

下面是我爲此目的嘗試的代碼。

public class SecurityAppConfig { 

@Configuration 
@Order(1) 
public static class APISecurityConfig extends WebSecurityConfigurerAdapter { 

private CustomAuthenticationManager1 manager1 = new CustomAuthenticationManager1(); 

@Override 
protected void configure(HttpSecurity http) throws Exception { 
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() 
     .formLogin().disable().csrf().disable().cors().disable().logout().disable(); 

    if (manager1 != null) { 
    http.addFilterAfter(new Filter1(manager1), 
     AnonymousAuthenticationFilter.class); 

    } 

} 
} 


@Configuration 
@Order(2) 
public static class OtherApiSecurityConfig extends WebSecurityConfigurerAdapter { 

private AuthenticationManager2 manager2 = new AuthenticationManager2(); 

@Override 
protected void configure(HttpSecurity http) throws Exception { 
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() 
     .formLogin().disable().csrf().disable().cors().disable().logout().disable(); 

    if (manager2 != null) { 
    http.antMatchers("/api/**").addFilterAfter(new Filter2(manager2), 
     AnonymousAuthenticationFilter.class); 
    } 
} 
} 

} 

在應用程序的時間啓動兩個濾波器得到與他們的經理註冊,但是當這個(「/ API/**」)請求到達它進入第一個認證的過濾器,但從來沒有進入到第二過濾器。如果我刪除第一個過濾器,那麼它可以正常工作,但會覆蓋其他api請求的過濾器。

下面是我是如何實現的管理人員和過濾

public class Filter1 extends AbstractAuthenticationProcessingFilter { 
    //implementation omitted for brevity. 
} 

public class Filter2 extends AbstractAuthenticationProcessingFilter { 
    //implementation omitted for brevity. 
} 

public class AuthenticationManager1 implements AuthenticationManager { 
    //implementation omitted for brevity. 
} 

public class AuthenticationManager2 implements AuthenticationManager { 
    //implementation omitted for brevity. 
} 

我如何能得到這個工作有什麼想法。

回答

2

我不認爲你需要兩個配置你的情況。我不明白你爲什麼需要實現自己的身份驗證管理器,甚至其中的兩個。我想你應該使用共享身份驗證管理器,實施自己的AuthenticationProvider(每種身份驗證類型一個),並實現您自己的身份驗證令牌。除此之外,由於您使用的AbstractAuthenticationProcessingFilter爲你過濾器的基類 - 你可以設置filterProcessesUrl進去,這樣你的過濾器知道的URL應該應用到。因此,在短暫的:

認證令牌:

public class MyAuth1AuthenticationToken extends AbstractAuthenticationToken { 
    // Implementation depends on you auth scheme (you can look on 
    // `UsernamePasswordAuthenticationToken` for example) 
} 

public class MyAuth2AuthenticationToken extends AbstractAuthenticationToken { 
    // ... 
} 

驗證提供:

public class MyAuth1AuthenticationProvider implements AuthenticationProvider { 
    @Override 
    public Authentication authenticate(Authentication authentication) 
     throws AuthenticationException { 
     // Implementation really depends on you auth scheme (you can look on 
     // `AbstractUserDetailsAuthenticationProvider` for example) 
    }   

    @Override 
    public boolean supports(Class<?> authentication) { 
     // By this we're saying that this auth provider is responsible for our MyAuth1 auth request 
     return (MyAuth1AuthenticationToken.class.isAssignableFrom(authentication)); 
    } 
} 

public class MyAuth2AuthenticationProvider implements AuthenticationProvider { 
    @Override 
    public Authentication authenticate(Authentication authentication) 
     throws AuthenticationException { 
     // ... 
    }   

    @Override 
    public boolean supports(Class<?> authentication) { 
     return (MyAuth2AuthenticationToken.class.isAssignableFrom(authentication)); 
    } 
} 

過濾器:

public class Auth1Filter extends AbstractAuthenticationProcessingFilter { 

    public Auth1Filter(AuthenticationManager authManager, String defaultFilterProcessesUrl) { 
     super(defaultFilterProcessesUrl); 
     setAuthenticationManager(authManager); 
    } 

    @Override 
    public Authentication attemptAuthentication(HttpServletRequest request, 
     HttpServletResponse response) throws AuthenticationException { 

     // extract user info here 
     // ... 

     // populate auth request with your info 
     MyAuth1AuthenticationToken authRequest = new MyAuth1AuthenticationToken(...); 

     // authenticate 
     return this.getAuthenticationManager().authenticate(authRequest); 
    } 
} 

public class Auth2Filter extends AbstractAuthenticationProcessingFilter { 

    public Auth2Filter(AuthenticationManager authManager, String defaultFilterProcessesUrl) { 
     super(defaultFilterProcessesUrl); 
     setAuthenticationManager(authManager); 
    } 

    @Override 
    public Authentication attemptAuthentication(HttpServletRequest request, 
     HttpServletResponse response) throws AuthenticationException { 

     // extract user info here 
     // ... 

     // populate auth request with your info 
     MyAuth2AuthenticationToken authRequest = new MyAuth1AuthenticationToken(...); 

     // authenticate 
     return this.getAuthenticationManager().authenticate(authRequest); 
    } 
} 

安全配置:

@Configuration 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Override 
public void configure(AuthenticationManagerBuilder auth) throws Exception 
{ 
    // registering our providers 
    auth 
     .authenticationProvider(new MyAuth1AuthenticationProvider()) 
     .authenticationProvider(new MyAuth2AuthenticationProvider()); 
} 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
      .sessionManagement() 
      .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
      .and() 
      .formLogin().disable() 
      .csrf().disable() 
      .cors().disable() 
      .logout().disable(); 

     AuthenticationManager authManager = http.getSharedObject(AuthenticationManager.class); 

     http.addFilterAfter(new Auth1Filter(authManager, "/**"), BasicAuthenticationFilter.class); 
     http.addFilterAfter(new Auth2Filter(authManager, "/api/**"), BasicAuthenticationFilter.class); 
    } 
} 

希望它能幫助。

+0

問題是我在延長它實現了Authenticaton經理定製authenticatication遺留代碼,現在如果我不通過延長WebSecurityConfigurerAdapter然後我不得不使用已實施的管理器,它在不同的認證請求創建一個新的配置邏輯,因此我不得不用新的管理器創建一個新的配置註冊過濾器,但是當一個API請求到來時,它永遠不會過濾第二個配置。 我試圖實現基於該方法「http.getSharedObject(AuthenticationManager.class)」第二個配置你的建議,但返回null。 – user2912611

+0

有你不能有兩個配置Spring Security的過濾器的點包含過濾器鏈的列表,並分派到與其匹配所以在我的情況下,它總是指派給第一鏈的第一鏈的請求。 (https://spring.io/guides/topicals/spring-security-architecture/)。但是,你能幫我理解爲什麼有多個管理器是錯誤的,爲什麼springSecurityFilterChain bean只需要一個認證管理器bean? – user2912611