Spring Security、カスタムGenericFilterBean、AuthenticationProvider実装を備えたSpring4を使用しています。新しいセッションを作成するためのURLを除いて、ほとんどの場合URLを保護しています:/ v2 / session(たとえば、ユーザー名とパスワードに基づいてログインし、認証を必要とする後続のリクエストで使用される認証トークンを返します):次のように構成されています。
@Configuration
@ComponentScan(basePackages={"com.api.security"})
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private ApiAuthenticationProvider apiAuthenticationProvider;
@Autowired
private AuthTokenHeaderAuthenticationFilter authTokenHeaderAuthenticationFilter;
@Autowired
private AuthenticationEntryPoint apiAuthenticationEntryPoint;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(apiAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(authTokenHeaderAuthenticationFilter, BasicAuthenticationFilter.class) // Main auth filter
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests()
.antMatchers(HttpMethod.POST, "/v2/session").permitAll()
.anyRequest().authenticated();
http.exceptionHandling()
.authenticationEntryPoint(apiAuthenticationEntryPoint);
}
}
authTokenHeaderAuthenticationFilterは、すべてのリクエストに応じて実行され、リクエストヘッダからトークンを取得します。
/**
* Main Auth Filter. Always sets Security Context if the Auth token Header is not empty
*/
@Component
public class AuthTokenHeaderAuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
final String token = ((HttpServletRequest) request).getHeader(RequestHeaders.AUTH_TOKEN_HEADER);
if (StringUtils.isEmpty(token)) {
chain.doFilter(request, response);
return;
}
try {
AuthenticationToken authRequest = new AuthenticationToken(token);
SecurityContextHolder.getContext().setAuthentication(authRequest);
}
} catch (AuthenticationException failed) {
SecurityContextHolder.clearContext();
return;
}
chain.doFilter(request, response); // continue down the chain
}
}
カスタムapiAuthenticationProviderは、ヘッダーで提供されたトークンに基づいてすべての要求を認証しようとします。認証が失敗した場合、AccessExceptionをスローし、クライアントはHTTP401応答を受信します。
@Component
public class ApiAuthenticationProvider implements AuthenticationProvider {
@Autowired
private remoteAuthService remoteAuthService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
AuthenticationToken authRequest = (AuthenticationToken) authentication;
String identity = null;
try {
identity = remoteAuthService.getUserIdentityFromToken(authRequest.getToken());
} catch (AccessException e) {
throw new InvalidAuthTokenException("Cannot get user identity from the token", e);
}
return new AuthenticationToken(identity, authRequest.getToken(), getGrantedAuthorites());
}
}
これは、認証を必要とする要求に対しては完全に正常に機能します。これは、認証ヘッダーが含まれていない/ v2 / sessionリクエストに対しては正常に機能します。ただし、ヘッダー(またはCookie内-コードサンプルには表示されていません。クライアントがヘッダーをクリアしなかった場合、またはリクエストとともにCookieを送信し続けた場合)に期限切れの認証トークンがある/ v2 / sessionリクエストの場合)セキュリティコンテキストが初期化され、apiAuthenticationProviderが例外をスローし、HTTP401でクライアントに応答します。
以来/ V2 /セッションがように構成されています
http.authorizeRequests()
.antMatchers(HttpMethod.POST, "/v2/session").permitAll()
Spring Securityは、ApiAuthenticationProvider.authenticate()を呼び出す前にそれを判断することを期待しています。フィルタまたは認証プロバイダーがpermitAll()として構成されたURLの例外を無視する/スローしない方法は何ですか?
Springセキュリティフィルタは、リクエストの承認チェックが実行される前にトリガーされます。承認チェックが機能するためには、要求がフィルターを通過し、Springセキュリティコンテキストが設定されている(または、認証資格情報が渡されたかどうかによっては設定されていない)と想定されます。
フィルタには、トークンがない場合にフィルタチェーン処理を続行するチェックがあります。残念ながら、そうである場合は、認証のためにプロバイダーに渡されます。トークンの有効期限が切れているため、例外がスローされ、401が取得されます。
最善の策は、公開されていると見なすURLのフィルター実行をバイパスすることです。これは、フィルター自体または構成クラスで実行できます。次のメソッドをSecurityConfig
クラスに追加します。
@Override
public void configure(WebSecurity webSecurity) {
webSecurity.ignoring().antMatchers(HttpMethod.POST, "/v2/session");
}
これが行うことは、URLをAuthTokenHeaderAuthenticationFilter
完全にバイパスすることですPOST /v2/sessions
。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加