Spring Securityでフォーム認証を実装する(設定編)ー Spring Security ver 5.7.0以降6.0.0より前の場合

SpringSecirityはバージョンごとに設定の書き方が大幅に変更されている。
ここでは、バージョンごとに記載方法が大きく変更となっているJavaConfig の記載方法についてまとめる。

バージョンによらない部分の実装については、下記の記事参照。

olafnosuke.hatenablog.com


@EnableWebSecurityアノテーションを付ける

このクラスに記載の設定を適用したSpringSecurityによるフォーム認証を有効化するために、「@EnableWebSecurityアノテーションをクラスに付与する。

@EnableWebSecurityは合成アノテーションであり、内部に「@Configurationアノテーションも持っているため、
このクラスはJavaConfigクラスではあるものの「@Configurationアノテーションの付与を省略することができる。

@EnableWebSecurity
public class FormSecurityConfiguration {
}

パスワードのエンコーダクラスをDIコンテナに登録する

作成したJavaConfigクラス内でパスワードのエンコーダクラスをDIコンテナに登録するメソッドを実装する。
使用するエンコーダはプロジェクトの仕様により適切なものを選定する。

/**
 * パスワードのエンコーダーをDIコンテナに登録する。<br>
 */
@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

認証の設定を行うメソッドを実装する。

Spring Security ver5.7.0以降では、「org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter」が非推奨となり、「SecurityFilterChain」を使用した設定が推奨されている。

このメソッドでは、以下の設定を実施している。

  • 認証マネージャーの構築
  • 認証の対象とするURLの設定
  • フォーム認証の設定
  • ログアウトの設定
/**
 * {@link SecurityFilterChain}をDIコンテナに登録する。<br>
 * 
 * @param http
 *          {@link HttpSecurity}
 * @return {@link SecurityFilterChain}
 * @throws Exception
 *           セキュリティ設定時に例外が発生した場合
 */
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
}
認証マネージャーの構築

Spring Security ver5.7.0より前では、引数が「AuthenticationManagerBuilder」なconfigureメソッドで設定していた内容である。
パスワードエンコーダーとユーザ情報を構築するサービスを設定した認証マネージャーを構築する。

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    AuthenticationManagerBuilder builder = http.getSharedObject(AuthenticationManagerBuilder.class);
    builder.userDetailsService(new LocalUserDetailService(passwordEncoder()));
    AuthenticationManager manager = builder.build();
}
認証の対象とするURLの設定

フォーム認証の対象とするURL、対象外とするURLを設定する。
静的ファイルのパスやログイン画面のURLを認証対象外となるように設定している。

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    AuthenticationManagerBuilder builder = http.getSharedObject(AuthenticationManagerBuilder.class);
    builder.userDetailsService(new LocalUserDetailService(passwordEncoder()));
    AuthenticationManager manager = builder.build();

    http.authenticationManager(manager)
        .authorizeHttpRequests()
        // 認証対象外のURL指定(静的ファイル、エラーページ遷移のURL)
        .mvcMatchers("/images/**", "/css/**", "/js/**", "/webjars/**", "/authorization/**", "/filter-error").permitAll()
        // ログイン画面のURLも認証対象外とする
        .antMatchers("/login").permitAll()
        // 上記のURL以外は認証が必要
        .anyRequest().authenticated();
}
フォーム認証の設定

フォーム認証で使用するログイン画面へ遷移するURL、フォーム認証成功後に遷移するURLを指定する。
また、認証成功時にユーザオブジェクトを構築するハンドラーを追加する。

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http.formLogin()
        // フォーム認証のログイン画面のURL
        .loginPage("/login")
        // 認証成功時に遷移するURL
        .defaultSuccessUrl("/")
        // Form認証成功時にユーザオブジェクトを構築するハンドラーを追加する
        .successHandler(new LocalAuthenticationSuccessHandler());
}
ログアウトの設定

ログアウトURLやログアウト成功時の遷移先URLの設定を行う。
また、ログアウト時にCookieの値やセッションを無効化するよう設定を行う。

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http.logout()
        // ログアウトのURL
        .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
        // ログアウト成功時のURL(ログイン画面に遷移)
        .logoutSuccessUrl("/login")
        // Cookieの値を削除する
        .deleteCookies("JSESSIONID")
        // セッションを無効化する
        .invalidateHttpSession(true).permitAll();
}

最終的に作成されるJavaConfigクラス

import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import jp.co.sample.web.authentication.handler.LocalAuthenticationSuccessHandler;
import jp.co.sample.web.authentication.user.LocalUserDetailService;

/**
 * フォーム認証する際に使用するSpring Securityの定義クラス。<br>
 */
@EnableWebSecurity
public class FormSecurityConfiguration {

  /**
   * パスワードのエンコーダーをDIコンテナに登録する。<br>
   * 
   * @return {@link PasswordEncoder}
   */
  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

  /**
   * {@link SecurityFilterChain}をDIコンテナに登録する。<br>
   * 
   * @param http
   *          {@link HttpSecurity}
   * @return {@link SecurityFilterChain}
   * @throws Exception
   *           セキュリティ設定時に例外が発生した場合
   */
  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    AuthenticationManagerBuilder builder = http.getSharedObject(AuthenticationManagerBuilder.class);
    builder.userDetailsService(new LocalUserDetailService(passwordEncoder()));
    AuthenticationManager manager = builder.build();

    http.authenticationManager(manager)
        .authorizeHttpRequests()
        // 認証対象外のURL指定(静的ファイル、エラーページ遷移のURL)
        .mvcMatchers("/images/**", "/css/**", "/js/**", "/webjars/**", "/authorization/**", "/filter-error").permitAll()
        // ログイン画面のURLも認証対象外とする
        .antMatchers("/login").permitAll()
        // 上記のURL以外は認証が必要
        .anyRequest().authenticated();

    // フォーム認証の設定
    http.formLogin()
        // フォーム認証のログイン画面のURL
        .loginPage("/login")
        // 認証成功時に遷移するURL
        .defaultSuccessUrl("/")
        // Form認証成功時にユーザオブジェクトを構築するハンドラーを追加する
        .successHandler(new LocalAuthenticationSuccessHandler());

    // ログアウト処理の設定
    http.logout()
        // ログアウトのURL
        .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
        // ログアウト成功時のURL(ログイン画面に遷移)
        .logoutSuccessUrl("/login")
        // Cookieの値を削除する
        .deleteCookies("JSESSIONID")
        // セッションを無効化する
        .invalidateHttpSession(true).permitAll();

    return http.build();
  }

}