前回、モダンなフロントエンド(SPA)との連携において、CORS(クロスオリジンリソース共有)の設定が不可欠であることを学びました。
SPAとの連携でしばしば採用されるのが、JWT(JSON Web Token)という認証方式です。これまでに学んだセッションベースの認証と異なり、JWTはステートレス(状態を持たない)な認証を実現し、システムのスケーラビリティを大きく向上させます。
今回は、JWTとは何か、なぜSPAで好まれるのか、そしてSpring SecurityにJWT認証を組み込むための基本を学びます。
1. セッション認証 vs. JWT認証
Spring Securityのデフォルトであるセッションベース認証は、サーバーが認証情報をセッションという形で保持します。
| 認証方式 | 認証情報の保持場所 | 特徴 |
| セッション認証 | サーバー側のメモリやDB | サーバーが状態を管理(ステートフル)。シングルサーバーでは簡単だが、サーバー増設時にセッション共有が必要。 |
| JWT認証 | クライアント側(ブラウザのローカルストレージなど) | サーバーが状態を管理しない(ステートレス)。認証情報をトークンに含め、リクエストごとに検証する。 |
JWT認証は、サーバーが増減してもセッション共有の仕組みが不要なため、マイクロサービスや大規模な分散システムにおいて非常に有利です。
2. JWT(JSON Web Token)の構造
JWTは、認証情報やユーザー情報(クレームと呼びます)を格納した、署名付きの文字列です。以下の3つのパートがピリオド(.)で区切られて構成されます。
2-1. JWTの3つのパート
- Header(ヘッダー): トークンのタイプ(JWT)と、署名に使われたアルゴリズム(例:HMAC SHA256)を定義します。
- Payload(ペイロード): クレーム(Claims)と呼ばれる実際のユーザー情報を格納します。ユーザーID、権限(Role)、トークンの発行時刻や有効期限などが含まれます。
- Signature(署名): ヘッダーとペイロードを、サーバーが持つ秘密鍵で暗号化したハッシュ値です。
2-2. 署名の役割(改ざん検知)
署名が存在することで、サーバーは以下のことを確認できます。
- 正真性: トークンが本物のサーバーによって発行されたものかを確認できる。
- 改ざん検知: トークンの内容(ペイロード)が、発行後に第三者によって改ざんされていないかを確認できる。
注意: ペイロードは誰でもデコードして中身を見ることができます。機密情報(パスワードなど)を格納してはいけません。
3. Spring SecurityへのJWT組み込み
Spring SecurityでJWT認証を有効にするには、主に以下の手順が必要です。
3-1. セキュリティ設定の変更(ステートレス化)
まず、セッションを使わないステートレスな認証を行うよう、Spring Securityに設定します。
Java
import org.springframework.security.config.http.SessionCreationPolicy;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// セッションを使わないよう設定(最も重要)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// 認証されていないリクエストは全て弾く
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
// CSRF対策もステートレス認証では基本的に無効化(トークンで対策するため)
.csrf(csrf -> csrf.disable());
// ... JWT検証のためのカスタムフィルターを追加する(次項)
return http.build();
}
// ... PasswordEncoder, UserDetailsServiceなどのBean定義は継続
}
3-2. 認証後のJWT発行
ユーザーがログインに成功した後(UserDetailsService で認証が成功した後)、サーバーは秘密鍵を使ってJWTを生成し、それをクライアント(ブラウザ)に返します。
3-3. リクエストごとのJWT検証(カスタムフィルター)
クライアントは、発行されたJWTをHTTPヘッダー(通常は Authorization: Bearer <JWT>の形式)に入れて、APIリクエストを送信します。
Spring Securityでは、このリクエストヘッダーからJWTを取り出し、署名を検証し、ペイロードの有効期限を確認し、認証情報を SecurityContext にセットするためのカスタムフィルターを実装する必要があります。
Java
// JWTFilter.java (概念)
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(...) {
// 1. リクエストヘッダーからJWTを取得
// 2. JWTの署名と有効期限を検証
// 3. 認証がOKであれば、UserDetailsオブジェクトを作成
// 4. SecurityContextHolder.getContext().setAuthentication(Authentication) で認証情報をセット
}
}
このカスタムフィルターを SecurityFilterChain に追加することで、以降のControllerやServiceの処理で、認証されたユーザー情報(権限など)を利用できるようになります。
✅ 本日のまとめ
- **JWT(JSON Web Token)**は、ステートレスな認証を実現し、スケーラビリティに優れるため、SPAやマイクロサービスで広く利用される。
- JWTは、ヘッダー、ペイロード、署名の3パートからなり、署名によって改ざん検知が可能である。
- JWTのペイロードは誰でも見られるため、機密情報を格納してはならない。
- Spring SecurityでJWTを導入するには、セッション管理を
SessionCreationPolicy.STATELESSに設定し、リクエストヘッダーのJWTを処理するためのカスタムフィルターを実装する必要がある。
🔔 次回予告
ここまで、Webアプリケーション構築に必要な全ての要素を学びました。
次回からは、アプリケーション開発の次のステップである「テスト」というテーマに進みます。次回は、Spring Bootにおける**単体テスト(JUnit 5)**の書き方と、DIコンテナを意識しないテストの基本を学びます。
次回:【第38回】堅牢なシステムのために!〜単体テスト(Unit Test)の基本〜 にご期待ください!


コメント