Skip to content

Spring Security 6.0への移行

問題

Spring Security 6.0(Spring Boot 3.0以降)へ移行する際、以下の非推奨化・削除された機能によって既存のセキュリティ設定が動作しなくなるという問題が発生します:

  1. authorizeRequests() - リクエスト認可設定メソッドの廃止
  2. antMatchers() - URLパスパターンマッチングメソッドの削除
  3. @EnableGlobalMethodSecurity(prePostEnabled = true) - アノテーションの削除

これらの変更により、リクエスト認可設定やメソッドレベルのセキュリティアノテーション機能が従来通り動作しなくなります。

エラー例

移行時に遭遇する典型的なエラー:

authorizeRequests() cannot be resolved
antMatchers() cannot be resolved
Cannot resolve @EnableGlobalMethodSecurity

解決策

Spring Security 6.0では新しいAPIが導入されています。以下の変更を適用することで問題を解決できます。

1. リクエスト認可設定の移行

authorizeRequests()antMatchers() を置き換える方法:

java
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
    return httpSecurity
        .csrf(csrf -> csrf.disable())
        .authorizeHttpRequests(auth -> auth  // authorizeRequests()から変更
            .requestMatchers("/token/**").permitAll()  // antMatchers()から変更
            .anyRequest().authenticated()
        )
        .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .oauth2ResourceServer(spec -> spec.jwt(Customizer.withDefaults())) // 修正されたOAuth2設定
        .httpBasic(Customizer.withDefaults())
        .build();
}

主な変更点:

  • authorizeRequests()authorizeHttpRequests()
  • antMatchers()requestMatchers()
  • requestMatchers()antMatchers(), mvcMatchers(), regexMatchers() の代替として統合

2. メソッドセキュリティアノテーションの有効化

@EnableGlobalMethodSecurity を以下のように置き換え:

java
@Configuration
@EnableWebSecurity
@EnableMethodSecurity  // @EnableGlobalMethodSecurityから変更
public class SecurityConfig {
    // クラス実装
}

重要な点:

  • prePostEnabled = true はデフォルトで有効なため不要
  • @PreAuthorize@PostAuthorize アノテーションが自動的にサポートされる

3. OAuth2リソースサーバーの設定更新

OAuth2ResourceServerConfigurer::jwt から新しい設定形式へ移行:

java
.oauth2ResourceServer(spec -> spec.jwt(Customizer.withDefaults()))

4. CSRF無効化のアップデート

Spring Security 6.1以降では最新の無効化方法を適用:

java
.csrf(AbstractHttpConfigurer::disable)

完全な設定例

すべての変更を適用した最終的なSecurityConfigクラス:

java
package org.sid.securityservice.config;

import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity  // 変更ポイント
public class SecurityConfig {
    private RsakeysConfig rsakeysConfig;
    private PasswordEncoder passwordEncoder;

    public SecurityConfig(RsakeysConfig rsakeysConfig, PasswordEncoder passwordEncoder) {
        this.rsakeysConfig = rsakeysConfig;
        this.passwordEncoder = passwordEncoder;
    }

    @Bean
    public AuthenticationManager authenticationManager(UserDetailsService userDetailsService){
        var authProvider = new DaoAuthenticationProvider();
        authProvider.setPasswordEncoder(passwordEncoder);
        authProvider.setUserDetailsService(userDetailsService);
        return new ProviderManager(authProvider);
    }

    @Bean
    public UserDetailsService inMemoryUserDetailsManager(){
        return new InMemoryUserDetailsManager(
                User.withUsername("user1").password(passwordEncoder.encode("1234")).authorities("USER").build(),
                User.withUsername("user2").password(passwordEncoder.encode("1234")).authorities("USER").build(),
                User.withUsername("admin").password(passwordEncoder.encode("1234")).authorities("USER","ADMIN").build()
        );
    }
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                .csrf(AbstractHttpConfigurer::disable)  // 変更ポイント
                .authorizeHttpRequests(auth -> auth  // 変更ポイント
                    .requestMatchers("/token/**").permitAll()  // 変更ポイント
                    .anyRequest().authenticated()
                )
                .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .oauth2ResourceServer(spec -> spec.jwt(Customizer.withDefaults()))  // 変更ポイント
                .httpBasic(Customizer.withDefaults())
                .build();
    }
    
    @Bean
    JwtDecoder jwtDecoder(){
        return NimbusJwtDecoder.withPublicKey(rsakeysConfig.publicKey()).build();
    }
    
    @Bean
    JwtEncoder jwtEncoder(){
        JWK jwk= new RSAKey.Builder(rsakeysConfig.publicKey()).privateKey(rsakeysConfig.privateKey()).build();
        JWKSource<SecurityContext> jwkSource= new ImmutableJWKSet<>(new JWKSet(jwk));
        return new NimbusJwtEncoder(jwkSource);
    }
}

変更の背景と影響

設計思想の変化

Spring Security 6.xの変更点は、以下を目的としています:

  • 設定APIの統一化(requestMatchersによるマッチング方法の統合)
  • 宣言的スタイルの強調(ラムダ式による設定の明確化)
  • デフォルト値の合理的な設定(@EnableMethodSecurityのデフォルト動作)

主要な変更点の詳細比較

廃止要素代替実装変更点
authorizeRequests()authorizeHttpRequests()メソッド名の明確化・リクエスト処理への特化
antMatchers()requestMatchers()各種マッチャーのAPI統一(Ant, MVC, 正規表現を単一APIで対応)
@EnableGlobalMethodSecurity@EnableMethodSecurityアノテーション名の簡略化・デフォルト動作の最適化(prePostEnabled=true)
OAuth2ResourceServerConfigurer::jwtspec -> spec.jwt(Customizer.withDefaults())設定方法のモダン化

これらの変更により、より直感的でタイプセーフな設定が可能になり、コードの可読性と保守性が向上します。

ベストプラクティス

  1. 段階的な移行:大きな設定ファイルを一気に変更せず、機能単位で逐步移行
  2. テストの重要性
    • セキュリティルートの認可テストの更新
    • /token/**パスの認証不要テスト
    • 保護リソースへのアクセス制御テスト
  3. プロジェクト全体の影響評価
    • カスタムWebSecurityConfigurerAdapter実装の確認
    • メソッドレベルのセキュリティアノテーション動作検証

注意事項

移行後も以下の点を確認してください:

  • AuthenticationManager Beanの競合(複数定義されていないか)
  • カスタムUserDetailsServiceの互換性保持
  • パスワードエンコーダーの適切な設定

Spring Security 6.xへの移行はAPIの変更を伴いますが、新しい設定スタイルはより明示的で安全なセキュリティ構成を実現します。上記のガイドラインに従って効率的に移行してください。