この記事はラクスアドベントカレンダーの17日目の記事です。
はじめに
最近Spring Securityを触る機会があったのですが、「設定クラスを書けばなんかできるけど、内部的にどんな動きをしてるかよくわからない」というものが正直な感想でした。
ということで今回は「Spring Securityがやっていること」についてまとめていきたいと思います。
Spring Securityとは
Spring Securityは、Springベースのアプリケーションに、認証 (BASIC認証、OpenID認証など)、認可 (権限によるアクセス許可、OAuth 2.0など)、その他多数のセキュリティ対策を可能にするフレームワークです。
Spring Securityの仕組み
Spring Securityはサーブレットフィルタの仕組みを使用して各種セキュリティ機能を実現しています。
絵にすると以下のようなイメージです。
- クライアントによるWebアプリケーションへのリクエスト
- Spring SecurityのFilterChainProxyクラスがクライアントのリクエストを受け取り、HttpFirewallインタフェースのメソッドを呼び出してHttpServletRequestとHttpServletResponseに対してファイアフォール機能を組み込む。
- Security Filterクラスに処理を委譲する。
- 各フィルタの処理が正常に終了すると後続のサーブレットフィルタが呼び出される。
- すべてのフィルタ処理が正常終了した後、Webアプリケーション内のリソースへアクセスする。
- Webアプリケーションからのレスポンス。
FilterChainProxy
ユーザからのリクエストを最初に受けるクラスでFilterChainProxy自身はセキュリティ機能を持ちませんが、各種セキュリティ機能の流れをコントロールします。
HttpFirewall
ファイアフォール機能を組み込むためのインターフェースです。
クライアントから受信したリクエストの検証や、サポートしていないリクエストを拒否するといった設定が可能です。
SecurityFilterChain
クライアントから受信したリクエストに対して適用するSecurityFilterを管理するためのインタフェースです。
SecurityFilter
SecurityFilterを適用することで、リクエストごとに必要なセキュリティ対策を実現することが可能です。
サンプルコードで確認してみる
大枠の概要はとらえられましたが、コードと照らし合わせてみないと何ともしっくりきませんでした。
ということで、Spring Securityの設定クラスの実装を確認していきます。
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/css/**", "/js/**").permitAll()
.antMatchers("/admin/**").hasAuthority("ROLE_ADMIN")
.anyRequest().authenticated();
}
}
@EnableWebSecurity
をつけることでSpring Securityが有効になり、後続のフィルタ処理が行われるようになりますが、いまいち上述の絵とつながりません。
@EnableWebSecurity
にヒントがありそうなので実装を確認していきます。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
HttpSecurityConfiguration.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
boolean debug() default false;
}
いくつかの設定クラスを読み込んでいるようですね。
その中の1つであるWebSecurityConfigurationのドキュメントを見てみると、、、
WebSecurity を使用して、Spring Security の Web ベースのセキュリティを実行する FilterChainProxy を作成します。次に、必要な Bean をエクスポートします。WebSecurityConfigurerAdapter を継承して Configuration として公開するか、WebSecurityConfigurer を実装して Configuration として公開することにより、WebSecurity をカスタマイズできます。この構成は、EnableWebSecurity を使用するときにインポートされます。
ここでFilterChainProxyが登場してきました。
つまり、@EnableWebSecurity
を付与することで FilterChainProxy が生成され、絵の構成が作られることでSpring Security の機能が有効になるという仕組みのようです。
次は、SecurityConfig.java
に戻り、各種セキュリティ対策(≒SecurityFilterChain)がどのように実現されているのかを確認してみます。
SecurityConfig.java
はWebSecurityConfigurerAdapterを継承することで SecurityFilterChain を構築することができるようになっています。
WebSecurityConfigurerAdapter
のconfigureメソッドをオーバライドすることでSecurityFilterChainをカスタムし、任意の認証機能を持ったSecurityFilterChainや、特定のリクエストに制限を持たせるSecurityFilterChainを構築することができます。
ここまでに確認したことをSecurityConfig.java
に反映するとこんな感じです。
@EnableWebSecurity // Spring Securityの有効化。FilterChainProxyの構築
public class SecurityConfig extends WebSecurityConfigurerAdapter { // SecurityFilterChainの構築
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/css/**", "/js/**").permitAll()
.antMatchers("/admin/**").hasAuthority("ROLE_ADMIN")
.anyRequest().authenticated();
//各フィルタのカスタマイズ
}
}
まとめ
ということで、Spring Securityが何をやっているのかを紐解いていきました。処理の流れと、実際のソースを比較してみると思いのほか複雑ではない印象を受けました。
Spring Securityにセキュリティ対策を任せることで、自前で実装をしなくても良かったり、アプリケーション本体は業務に集中することができたりと、恩恵を受けることができますので上手に使っていきたいところです。
引き続きラクスアドベントカレンダーお楽しみください。