Spring Securityでログイン後に任意の処理を行なってからログイン前にアクセスしたページにリダイレクトする

こんにちは、エキサイト株式会社の平石です。

今回は、Spring Securityでログイン後に任意の処理を行なってからログイン前にアクセスしたページにリダイレクトする方法をご紹介します。

はじめに

Spring SecurityはSpringで利用できる、認証とアクセス制御のためのフレームワークです。
IDとパスワードによるフォームログインやOAuth2ログインなど、さまざまな認証・アクセス制御の設定を行うことができます。

通常、ログインが必要なページに非ログイン状態でアクセスした場合、ログイン画面を表示しログインが必要なことをユーザーに伝えます。
そして、ログインが成功した場合には、ユーザーがアクセスしようとしていたページにリダイレクトしてあげるのが親切でしょう。
Spring Securityはそのような挙動をデフォルトで提供してくれており、こちら側で特別に設定する必要はありません。
しかし、ユーザーのログイン成功後に何か別の処理をしたいような場合には、少し工夫が必要です。
例えば、ログインに関する情報をDBに保存する(ログを取るなど)、外部認証後にアプリケーション側で独自に認証処理を入れる、のようなことが考えられます。

今回はそのための方法をご紹介します。

環境

この記事のソースコードは以下の環境で動作確認をしています。

  • Java 21
  • SpringBoot 3.2.1
  • Gradle 8.5

実現方法

今回のソースコードは、OAuth2(Googleを利用)ログインを利用する際の例ですが、formLoginを利用する場合も同様な設定で実現可能です。

SpringSecuirty6系では、以下のようにすることでOAuth2ログインを設定することが可能です。

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    /**
     * Spring Securityの処理フィルタ設定
     *
     * @param http HttpSecurity
     * @return SecurityFilterChain
     * @throws Exception 例外
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(
                        auth -> auth
                                .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                                .requestMatchers(HttpMethod.GET, "/login/google").permitAll()
                                .requestMatchers(HttpMethod.GET, "/error").permitAll()
                                .anyRequest().authenticated()
                )
                .oauth2Login(
                        login -> login
                                .loginPage("/login/google")
                                .failureUrl("/login/google?error")
                                .permitAll()
                )
                .logout(
                        logout -> logout
                                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                                .clearAuthentication(true)
                                .deleteCookies("SESSION_ID")
                );

        return http.build();
    }

}

OAuth2認証の詳細な設定と説明は、今回の記事の範囲外であるため省きます。

認証成功時の挙動を変更するためには、successHandlerに任意の処理を実行するように記述したHandlerインスタンスを渡してあげます。

                .oauth2Login(
                        login -> login
                                .loginPage("/login/google")
                                .successHandler(ここにhandlerのインスタンスを渡す)
                                .failureUrl("/login/google?error")
                                .permitAll()
                )

デフォルトでは、SavedRequestAwareAuthenticationSuccessHandlerというものが利用されており、このHandlerによってログイン前にアクセスしていたページにリダイレクトするようにしているようです。

ログイン成功時に任意の処理を実行してからリダイレクトする場合には、このHandlerを継承した別のHandlerを作成し、これをsuccessHandlerに渡します。

@Component
public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    public CustomAuthenticationSuccessHandler() {
        super.setDefaultTargetUrl("/");
    }

    @Override
    public void onAuthenticationSuccess(
            HttpServletRequest request, HttpServletResponse response, Authentication authentication
    ) throws IOException, ServletException {
        // ここに任意の処理を記述する

        super.onAuthenticationSuccess(request, response, authentication);
    }
}

DefaultTargetUrlは、ログイン画面に直接アクセスした場合などで、元々アクセスしていたページが存在しない場合のデフォルトのリダイレクト先です。

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {
    private final CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
               // 〜 略 〜
                .oauth2Login(
                        login -> login
                                .loginPage("/login/google")
                                .successHandler(customAuthenticationSuccessHandler)
                                .failureUrl("/login/google?error")
                                .permitAll(true)
                )
                // 〜 略 〜

        return http.build();
    }
}

終わりに

今回は、Spring Securityでログイン後に任意の処理を行なってからログイン前にアクセスしたページにリダイレクトする方法をご紹介しました。

では、また次回。