概要
Spring Securityの認証まわりについて調べたので備忘録です。
概略図
リクエストに対して、SecurityFilterChainが適用されます。
認証に関してはデフォルトではUsernamePasswordAuthenticationFilterが担当します(指定パスに対して適用、例:/loginなど)。
FilterからAuthenticationManagerが呼ばれ認証の可否を決定します。
AuthenticationManagerは複数のAuthenticationProviderを持ち、各Providerに対して認証可否の処理を委譲します。
AuthenticationFilter
認証処理を行うURLに対して適用されます。
ユーザー入力のnullチェックを行い、入力情報を元にUsernamePasswordAuthenticationTokenを発行、Managerに対して、認証可否を委譲します。
※通常、パラメータはID、パスワードのみとなっているので、それ以上のパラメータを使用して認証を行う場合は、カスタムフィルターを作成します。
UsernamePasswordAuthenticationToken
AbstractAuthenticationTokenを継承した入力値と認証判断に使用するフィールドパラメータを持ったデータオブジェクトです。
各Providerはこのオブジェクトを受け取り、フィールドパラメータから認証可否を判断します。
AuthenticationManager
インターフェースorg.springframework.security.authentication.AuthenticationManagerです。
このインターフェースには1つだけメソッドが定義されています。
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
デフォルトの実装クラスはorg.springframework.security.authentication.ProviderManagerです。
ProviderManagerは実際にパスワード一致などの判定を行うAuthenticationProviderを配列で持っており、各Providerのauthenticateメソッドを呼び、認証判定を行います。
AuthenticationProvider
実際に認証判定を行うクラスです(例 パスワード一致など)。
前述の通り、Providerは複数登録することが可能です。
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider());
auth.authenticationProvider(authProvider2());
}
public AuthenticationProvider authProvider() {
return new AbstractUserDetailsAuthenticationProvider() {
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
//
}
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
// ログインに使用したい特定のユーザーを作成する処理
return user;
}
};
}
あまり使い時はないかもしれませんが、ProviderでUserDetailsを継承したユーザーを返すようにすると、
インメモリ認証のようにすることもできます。
Providerの登録はWebSecurityConfigurerAdapterを継承したコンフィグクラス下でBeanアノテーションをつけるだけでも良いです。
@Bean
public AuthenticationProvider authProvider() {
return new CustomAuthenticationProvider(passwordEncoder, authenticationService);
}
ProviderのretrieveUserメソッド内でDBへのユーザー情報を取得し、パスワードの一致確認を行うことで認証可否の判断を行います。
以上、簡単ですがまとめでした。
内部実装を見てみるとパスワードハッシュに対するタイミング攻撃対策などがあり興味深いですね。
SpringSecurity全体のまとめはこちらの記事が参考になります。
Spring Security 使い方メモ 基礎・仕組み