【Spring Boot】Spring Securityの基本を理解する

Java

こんにちは、かつコーチです。

spring-boot-starter-securityを依存関係に追加した瞬間、それまで自由にアクセスできていた画面が突然ログイン画面に切り替わって驚いた経験はありませんか。

これはSpring Securityが「デフォルトで全リクエストを認証必須にする」という安全側の設計になっているためです。

この記事では、Spring Securityの基本的な仕組みと、独自の認可ルールを設定する方法を解説します。

Spring Securityとは何か

認証と認可を一手に引き受けるフレームワーク

Spring Securityとは、Spring Boot向けの認証・認可フレームワークです。

認証(Authentication)は「このユーザーは誰か」を確認する処理で、認可(Authorization)は「このユーザーは何をしてよいか」を判定する処理です。

この2つは混同されがちですが、役割は明確に異なります。

Spring Securityは、この両方をSecurityFilterChainと呼ばれるフィルタの連鎖として実現しています。

なぜ自前で実装せずSpring Securityを使うのか

認証・認可を自前で実装すると、セッション管理・CSRF対策・パスワードの安全な保存など、考慮すべき項目が非常に多くなります。

これらを一つでも見落とすと、深刻な脆弱性につながります。

Spring Securityは、これらのセキュリティ対策の多くをデフォルトで有効な状態にして提供してくれるため、意識せずとも一定水準の安全性を確保できます。

実装手順

手順1:依存関係を追加する

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

この依存関係を追加しただけで、全エンドポイントが認証必須になり、ランダム生成されたパスワードでのBasic認証が有効になります。

起動時のログに以下のようなパスワードが出力されるので、これでログインできることを確認してください。

Using generated security password: 3f8e2c1a-....

手順2:SecurityFilterChainで認可ルールを定義する

Spring Boot 3.x系(Spring Security 6.x)では、WebSecurityConfigurerAdapterを継承する古い方式は廃止されており、SecurityFilterChainをBeanとして定義する方式が標準です。

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/", "/login", "/public/**").permitAll()
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin(Customizer.withDefaults());

        return http.build();
    }
}

requestMatchersに書いたパターンは上から順に評価されるため、範囲の広いルールを先に書くと、後続のルールが評価されずに無視されます。

つまずきやすい設定・注意点

/admin/**のような限定的なルールは、anyRequest().authenticated()よりも必ず前に書く必要があります。

// ❌ NG:anyRequest()を先に書くと、以降のルールは評価されない
http.authorizeHttpRequests(auth -> auth
    .anyRequest().authenticated()
    .requestMatchers("/admin/**").hasRole("ADMIN")
);

筆者は最初にこの順序を逆にしてしまい、「ADMINロールを持つユーザーしかアクセスできないはずの管理画面に、一般ユーザーでもログインさえしていれば入れてしまう」不具合を作り込んだことがあります。

authorizeHttpRequestsのルールは上から順に最初にマッチしたものが適用される、という仕様を必ず覚えておいてください。

よくあるつまずきポイント・エラー対処

❌ Before:Beanの定義漏れで意図しない挙動になる

SecurityConfigクラス自体を作らずにspring-boot-starter-securityだけ追加すると、Spring Bootの自動設定によるデフォルトのSecurityFilterChainが適用されます。

これは全リクエストを認証必須にする最も安全側の設定であり、多くの場合、開発中のアプリの要件とは合いません。

✅ After:明示的にSecurityFilterChainを定義する

前述の手順2のように、自前でSecurityFilterChainをBean定義すると、そちらが自動設定より優先されます。

意図しないデフォルト挙動に振り回されないためにも、Spring Securityを導入したら必ずSecurityConfigクラスを自作するのが実務での定石です。

応用・一歩先の使い方

ロールとオーソリティの違いを理解する

hasRole("ADMIN")は内部的にROLE_ADMINというオーソリティ(権限文字列)を持っているかを確認しています。

hasAuthority("ROLE_ADMIN")と書いても同じ結果になりますが、hasRoleROLE_のプレフィックスを自動で付けてくれる点が違います。

// 以下2つは等価
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/admin/**").hasAuthority("ROLE_ADMIN")

ROLE_が付かない権限(例:READ_PRIVILEGEのような細かい操作権限)を扱いたい場合は、hasAuthorityを使う場面が出てきます。

メソッドレベルでの認可

URLパターンだけでなく、メソッド単位でも認可ルールを設定できます。

@EnableMethodSecurity
@Configuration
public class MethodSecurityConfig {}
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long userId) {
    // 管理者のみ実行可能
}

URLパターンでは表現しづらい、細かい業務ロジック単位のアクセス制御が必要な場面で活躍します。

まとめ

この記事のポイント

  • Spring Securityは認証・認可を一手に引き受けるフレームワークで、デフォルトで安全側に倒れている
  • Spring Boot 3.x系ではSecurityFilterChainをBeanとして定義する
  • authorizeHttpRequestsのルールは上から順に評価されるため、限定的なルールを先に書く
  • @PreAuthorizeでメソッド単位の認可も可能

次に読むべき記事

Spring Securityの基本を押さえたら、次はフォームログインの具体的な実装を見ていきましょう。

→ 次の記事:フォームログイン機能を実装する

タグ: #SpringBoot #中級者向け #認証

タイトルとURLをコピーしました