Spring Security Web(2)
特定ヘッダでのチェック
続いて、特定のヘッダをチェックする方法を紹介します。
APIの場合、図3に示すトークンを使ったアクセス制御はよく行う手法です。管理者からのアクセスに限らず、トークンに応じて柔軟なアクセスコントロールが行いやすいため、こちらの方法がより多く使われるのかもしれません。
リスト4は、処理をより単純化し、X-Tokenという1つのヘッダ値でのチェックによって、アクセス制御を行うためのサンプルコードです。
public class WebHeaderSecurityConfiguration extends WebSecurityConfigurerAdapter {
// : 省略
// (1) フィルタを実装
public class HeaderCheckFilter extends AbstractPreAuthenticatedProcessingFilter {
private String headerName;
public HeaderCheckFilter(String headerName) {
this.headerName = headerName;
}
// (2) ヘッダ(X-Token)の値を返す
@Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
return request.getHeader(headerName);
}
@Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
return "";
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
HeaderCheckFilter filter = new HeaderCheckFilter("X-Token");
// (3) ヘッダのチェック
filter.setAuthenticationManager(new AuthenticationManager() {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String principal = (String) authentication.getPrincipal();
// X-Tokenのヘッダの値をチェックする
if(principal.equals("PASS")) {
// (4) 認証済みとして設定する
authentication.setAuthenticated(true);
}
else{
throw new BadCredentialsException("Token key error");
}
return authentication;
}
});
// 認証の対象となるパス
http.antMatcher("/admin/**");
// (5) フィルタの設定
http.addFilter(filter);
// 対象のすべてのパスに対して認証を有効にする
http.authorizeRequests().anyRequest().authenticated();
// : 省略
}
// : 省略
}
(1)でヘッダから必要な値を取り出すためのフィルタのクラスを定義します。
このクラスはAbstractPreAuthenticatedProcessingFilterインターフェースの実装クラスであり、getPreAuthenticatedPrincipalとgetPreAuthenticatedCredentialsのメソッドをオーバライドします。
今回のサンプルでは(2)のように指定されたヘッダの値のみを返します。
実際にヘッダのチェックは、(3)のようにsetAuthenticationManagerメソッド内で行い、ヘッダの値が問題なければ(4)のように認証済みとして設定します。
後は先ほどのBasic認証と同様に設定していきますが、Basic認証を使う代わりに作成したフィルタを使うように(5)の通りに設定します。
より自由に認証方法を実装したい場合には、今回の実装を参考にSpring Securityのリファレンスを参照するとよいと思います。
CSRF対策の設定
CSRFとは、クロスサイトリクエストフォージェリの略であり、図4(左)のようにサイトアクセス者が不正サイトを通じて意図しない登録処理などを行う攻撃の1つです。
この攻撃の一般的な防止法には、図4(右)のように、POSTやPUTなどのメソッドでそのページがリクエストをするときに、事前に作成したワンタイムパスワードと一緒にリクエストするといった方法があります。
Spring Securityを有効にするとデフォルトでこのCSRF対策が有効になります。しかしながら、APIサーバではこの対策は必要ないためリスト5のように機能を無効にします。
@Override
protected void configure(HttpSecurity http) throws Exception {
// : 省略
http.csrf().disable();
// : 省略
}
認証エラーの設定
認証エラーが発生したときには、APIサーバであればリスト6のようにJSON形式でエラーを返す必要があります。
{
"status": {
"code": "error",
"message": "Full authentication is required to access this resource"
}
}
その場合には、エラー時の処理をリスト6のように設定します。
@Override
protected void configure(HttpSecurity http) throws Exception {
// : 省略
// (1) エラーが生じたときのレスポンス設定
http.exceptionHandling().authenticationEntryPoint(new ErrorAuthEntryPoint());
}
// (2) エラー結果を記述するための実装
public class ErrorAuthEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
// (3) 実際のエラーを出力する
ErrorResponse errorResponse = Response.createErrorResponse(authException);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS,true);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
mapper.writeValue(response.getWriter(),errorResponse);
}
}
(1)で、認証エラーが生じた場合に、レスポンスを生成するクラスのインスタンスを設定します。
レスポンスを生成するクラスは、(2)のようにAuthenticationEntryPointインターフェースを実装したクラスを作成します。
実際のレスポンスは自由にであり、JSON形式でメッセージを出力するように(3)のようにjacksonライブラリのObjectMapperクラスを使って出力しています。
最後に
Spring Securityは今回紹介した機能以外にも非常に多くの機能があり、通常のWebアプリケーションを想定したFormを使ったログインやログアウトなどの機能も備えてます。
また、APIサーバでセキュリティをより強固にしたい場合にはOAuthなどのセキュリティ機能を使います。Spring SecurityはOAuthのプロバイダ機能もあるので、より強固なセキュリティにも対応可能です。
しかし、機能が高度である一方、記述方法が柔軟であり、なかなか正しい制限方法を明確に記述することが難しくもあります。このあたりは、慣れが必要だと思うので、さまざまなサンプルを見て他の人の記述方法なども参考にしてみてください。
今回まではサンプルアプリケーションを通じてSpring Bootでの各種スターター(ライブラリ等)の使い方を中心に紹介してきました。次回からはSpring Bootの仕組み側を見ていきます。
参考資料
- Spring
- Spring フレームワークのリファレンスドキュメント
- Spring Bootのリファレンスドキュメント
- Spring Bootのソースコード
- Spring Securityのリファレンスドキュメント

