【Spring MVC + Spring Security】認証イベントをハンドリングする方法

概要

Spring Securityの認証成功/失敗イベントをハンドリングする方法についてまとめた。

 

前提

以下の記事の続きとなる。

あわせて読みたい

概要 Spring Securityの認証機能に、パスワードのハッシュ化機能を導入する方法についてまとめた。   前提 以下の記事の続きとなる。

【Spring MVC + Spring Security】認証処理にパスワードのハッシュ化機能を導入する方法

 

認証イベント仕様

Spring SecurityはSpring Frameworkが提供するイベント制御の仕組みを利用して、認証成功/失敗イベントを通知する。
この仕組みを活用することで、認証処理に以下のような拡張機能を柔軟に追加できる。

 

・認証成功/失敗時の履歴をログ出力したり、DBに保存して監査記録を行う
・パスワードの連続失敗回数をカウントし、閾値を超えた場合にアカウントロック制御を行う

 

認証イベント発行~伝播までのざっくりとした流れは以下のようになる。

【Spring MVC + Spring Security】認証イベントをハンドリングする方法_認証イベント発行の流れ
▲認証イベント伝播までの流れ

 

①クライアントが認証リクエストを行う
②AuthenticationFilterにて、リクエストからユーザー名・パスワードなどの認証入力情報を取得する
③AuthenticationManagerを呼び出し、取得した認証入力情報を渡して認証処理を委譲する
④認証方式に対応するAuthenticationProviderが呼び出され、入力情報をもとに認証処理を実行する
⑤認証成功時はAuthenticationオブジェクトが返却され、失敗時はAuthenticationExceptionがスローされる
⑥認証結果に応じて、AuthenticationManagerがAuthenticationEventPublisherを通じて認証イベントを発行する
・成功時:AuthenticationSuccessEvent
・失敗時:例外種別に応じたAuthenticationFailureXXXEvent
⑦ApplicationEventPublisherが発行されたイベントをアプリケーション内部に通知する
⑧ApplicationListenerMethodAdapterが、イベントに対応するEventListenerアノテーションが付与されたメソッドを呼ぶ

 

 

実装

認証イベントに対応したイベントリスナーを追加する。

 

認証成功イベント

認証に成功した場合、Spring Securityは主に以下のイベントを発行する。

 

イベントクラス 説明
AuthenticationSuccessEvent AuthenticationManagerによる認証処理が成功したことを通知する。
このイベントをハンドリングすると、正しい認証情報がリクエストされたことを検知可能。
※後続の認証処理にてエラーが発生する可能性はある
InteractiveAuthenticationSuccessEvent インタラクティブ(フォームなどのUI操作による)なログイン認証がすべて成功したことを通知する。
このイベントをハンドリングすると、画面遷移を除いたすべての認証処理が成功したことを検知可能。

 

リスナー定義

認証成功時のイベントをハンドリングするイベントリスナーを作成する。

 

LoginSuccessListener.java


package com.example.prototype.biz.security.listener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.stereotype.Component;

@Component
public class LoginSuccessListener {
    private static final Logger logger = LoggerFactory.getLogger(LoginSuccessListener.class);

    @EventListener
    public void handleAuthenticationSuccessEvent(AuthenticationSuccessEvent event) {
        logger.info("\n★★ログイン成功: AuthenticationSuccessEventイベント★★\n");
    }

    @EventListener
    public void handleInteractiveAuthenticationSuccessEvent(InteractiveAuthenticationSuccessEvent event) {
        logger.info("\n★★ログイン成功: InteractiveAuthenticationSuccessEventイベント★★");

    }

}

 

@EventListener
public void handleAuthenticationSuccessEvent(AuthenticationSuccessEvent event) {

@EventListener
public void handleInteractiveAuthenticationSuccessEvent(InteractiveAuthenticationSuccessEvent event) {

メソッドに「org.springframework.context.event.EventListener」アノテーションを定義して
ハンドリングしたいイベントを引数に指定することで、自動でハンドリングできる。

 

認証失敗イベント

認証に失敗した場合、Spring Securityは様々な認証失敗ケースにあったイベントを発行する。
基本的にはすべての認証失敗イベントの基底クラスである、AbstractAuthenticationFailureEventをハンドリングすればOK。

 

イベントクラス 説明
AbstractAuthenticationFailureEvent すべての認証失敗イベントの抽象基底クラス。
このイベントをハンドリングすることで、あらゆる認証失敗ケースを一括検知可能。

 

リスナー定義

認証失敗時のイベントをハンドリングするイベントリスナーを作成する。

 

LoginFailureListener.java


package com.example.prototype.biz.security.listener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
import org.springframework.stereotype.Component;

@Component
public class LoginFailureListener {
    private static final Logger logger = LoggerFactory.getLogger(LoginFailureListener.class);
    
    @EventListener
    public void handleAbstractAuthenticationFailureEvent(AbstractAuthenticationFailureEvent event) {
        // ログイン失敗ユーザーのDB更新、ログ出力など
        logger.info("\n★★ログイン失敗(認証例外イベント): {}★★\n", event.getException().getClass());
    }
}

 

 

まとめ

 

☑ Spring Frameworkのイベント伝播の仕組みを利用することで、Spring Securityの認証結果イベント(成功/失敗)を検知できる

☑ イベントを検知するには、ルートアプリケーションコンテキスト配下にイベントリスナー用のBeanを定義する必要がある

☑ メソッドに@EventListenerを付与して引数に検知したいイベントクラスを指定することで、イベントをハンドリングできる

スポンサーリンク