カテゴリ: Spring認証(Spring Security) 更新日: 2025/08/24

JWTトークンの発行(Spring Security + JWT)を初心者向けにやさしく解説!

JWTトークンの発行(Spring Security + JWT)
JWTトークンの発行(Spring Security + JWT)

新人と先輩の会話形式で理解しよう

新人

「Spring Securityで認証をするってよく聞くんですが、最近はJWTも使うって聞きました。そもそもJWTって何なんですか?」

先輩

「JWTはJSON Web Tokenの略で、ログイン後にユーザー情報を含んだトークンを発行して、その後のリクエストに使う仕組みだよ。」

新人

「えっ、セッションとか使わないんですか?セッションIDで管理するのが普通じゃないんですか?」

先輩

「セッションを使う方法もあるけど、JWTは“ステートレス認証”っていって、サーバーに状態を持たせずに認証ができるんだ。今回はその基本を解説していこう!」

1. JWTとは何か?なぜ必要か?

1. JWTとは何か?なぜ必要か?
1. JWTとは何か?なぜ必要か?

JWT(ジェイダブリューティー)とは「JSON Web Token(ジェイソン・ウェブ・トークン)」の略称で、ログイン後のユーザー情報や認証状態を安全にやり取りするためのトークン技術です。ログイン認証において、セッションを使わずにユーザーを識別できる仕組みとして注目されています。

Spring BootなどのWebアプリでは、ログイン後にJWTトークンを発行し、クライアントに返します。以降のリクエストにはこのトークンをヘッダーに含めて送信することで、サーバーは誰からのリクエストかを判断できます。

JWTを使うと次のようなメリットがあります:

  • サーバー側にセッション情報を持たず、ステートレスでスケーラブル
  • 署名付きで改ざんが防げるため、安全性が高い
  • モバイルアプリやフロントエンドSPAとも相性が良い

JWTは3つの部分で構成されています:

  • ヘッダー:トークンの種類や署名アルゴリズムを記載
  • ペイロード:ユーザーIDなどの情報(クレーム)を格納
  • 署名:改ざんを防ぐためのハッシュ値

具体的には、以下のような形式で表現されます:


xxxxx.yyyyy.zzzzz

このようにして、JWTを使えば1つの文字列で認証状態を表現できるため、セッション管理の手間が省け、RESTfulなAPI設計にも適しています

2. Spring SecurityとJWTの関係とは?

2. Spring SecurityとJWTの関係とは?
2. Spring SecurityとJWTの関係とは?

Spring Securityは、Spring Frameworkで認証や認可を簡単に実装できるセキュリティ機能です。従来はセッションベースの認証が主流でしたが、JWTを組み合わせることでステートレスなAPI認証が可能になります。

Spring Securityでは、以下のような流れでJWT認証が行われます。

  1. ログインフォームでユーザーIDとパスワードを送信
  2. サーバーが認証に成功したら、JWTトークンを発行
  3. クライアントは受け取ったJWTをHTTPヘッダー(Authorization)に付けて以降のリクエストを送信
  4. サーバーはリクエストに含まれるJWTを検証し、ユーザー情報を取り出して認可を実施

以下はSpring SecurityでJWT認証を導入する際の基本的な構成図です:

  • 認証用のコントローラ(@Controller)
  • ユーザー情報を管理するサービス
  • JWTトークンを生成・検証するユーティリティクラス
  • Spring Securityのフィルターでトークンの検証処理

たとえば、以下のようなコントローラを用意して、ログインリクエストを受け付け、トークンを返すような処理になります。


@Controller
public class LoginController {

    @PostMapping("/login")
    public String login(@RequestParam String username,
                        @RequestParam String password,
                        HttpServletResponse response) {
        // 認証処理(省略)
        // JWTトークンを発行
        String token = jwtUtil.generateToken(username);

        // ヘッダーにトークンをセットして返却
        response.setHeader("Authorization", "Bearer " + token);
        return "loginSuccess";
    }
}

このように、Spring SecurityとJWTを組み合わせることで、安全かつ効率的なログイン認証が可能になります。特にモバイルアプリやSPA(シングルページアプリ)と連携する場合には、セッションよりもJWTが推奨されます。

3. JWTトークンを発行するための基本的な流れ

3. JWTトークンを発行するための基本的な流れ
3. JWTトークンを発行するための基本的な流れ

JWTトークンを使った認証の流れを理解するには、「ログイン処理」から「トークンの生成・返却」までの一連の処理を確認することが大切です。ここでは、Spring SecurityとJWTを使ったトークン発行の具体的なステップを丁寧に解説します。

【JWTトークン発行の基本的な流れ】
  1. ログイン画面からユーザーIDとパスワードを送信
  2. Spring Securityが認証処理を実行し、成功した場合に処理が進む
  3. ユーザー情報からトークンを生成する(JWTの発行)
  4. HTTPレスポンスのヘッダーやボディにトークンを設定してクライアントに返す

以下は、トークンを発行するための簡単なJWTユーティリティクラスの例です。


public class JwtUtil {

    private final String SECRET_KEY = "mysecretkey";

    public String generateToken(String username) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + 86400000); // 1日有効

        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }
}

このgenerateTokenメソッドは、ユーザー名を受け取ってトークンを生成します。トークンには有効期限(例:24時間)も設定されており、不正利用やセキュリティリスクを減らすために必須の設定です。

また、トークンはログイン成功時にレスポンスヘッダーやCookieなどでクライアントに渡されます。以下は前回のコントローラと合わせて使えるログイン処理の一部です。


@Controller
public class LoginController {

    private final JwtUtil jwtUtil = new JwtUtil();

    @PostMapping("/login")
    public String login(@RequestParam String username,
                        @RequestParam String password,
                        HttpServletResponse response) {
        // 認証成功したと仮定(実際はServiceでチェック)
        String token = jwtUtil.generateToken(username);
        response.setHeader("Authorization", "Bearer " + token);
        return "loginSuccess";
    }
}

このように、JWTトークンの発行処理は「認証 → トークン生成 → ヘッダー設定」というシンプルな構成で実現できます。Spring Securityと連携することで、より堅牢なセキュリティを確保できます。

4. JWTの中身とは?ペイロードや署名の意味を理解しよう

4. JWTの中身とは?ペイロードや署名の意味を理解しよう
4. JWTの中身とは?ペイロードや署名の意味を理解しよう

JWT(JSON Web Token)は、3つの部分に分かれています。それぞれの役割を理解することで、トークンの仕組みや安全性への理解が深まります。

【JWTの構造】

xxxxx.yyyyy.zzzzz
  • ヘッダー(Header)
    トークンの種類や使用する署名アルゴリズムを指定します。一般的には以下のような内容が入ります。
    
    {
      "alg": "HS256",
      "typ": "JWT"
    }
    
  • ペイロード(Payload)
    ユーザーIDやロールなどの情報(クレーム)を含みます。ここに含める情報は、アプリケーションの認可に使うことができます。
    
    {
      "sub": "user001",
      "name": "Taro Yamada",
      "iat": 1712100000,
      "exp": 1712186400
    }
    
  • 署名(Signature)
    ヘッダーとペイロードを暗号鍵で署名し、トークンが改ざんされていないことを保証します。これはSpring側で自動的に生成されます。

これら3つの情報は、ドット(.)で区切って1つの文字列になります。トークンはBase64エンコードされているため、専用のデコーダーを使えば中身を確認することも可能です(例:jwt.io)。

特に初心者が混乱しやすいのが「クレーム(Claim)」という用語です。これは、ペイロードに含まれる情報のことで、ユーザーのIDやロール、有効期限など、誰が・いつまで有効か・何ができるかといった情報を指します。

よく使われる標準クレームには以下のようなものがあります。

  • sub:トークンの対象(ユーザーID)
  • iat:トークンの発行日時(issued at)
  • exp:トークンの有効期限(expiration)

これらのクレームをもとに、Spring Securityでは認証と認可を実現します。

たとえば、「有効期限が切れているトークン」は自動的に認証エラーとなり、セキュリティ的に安全な状態が保たれます

また、トークンの中にロール情報(ROLE_USERなど)を含めておけば、アクセス制御(認可処理)にも活用できます。

5. Spring Securityと連携したJWT発行処理の実装例

5. Spring Securityと連携したJWT発行処理の実装例
5. Spring Securityと連携したJWT発行処理の実装例

ここでは、Spring SecurityとJWTを連携させた具体的な実装例を紹介します。今回の前提として、@Controllerを使ってログイン処理を記述する点を忘れずに押さえてください。

認証用のサービスでユーザー認証を行い、認証が成功した場合にJwtUtilクラスを使ってトークンを発行します。以下がその基本的な実装です。


@Controller
public class LoginController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public String login(@RequestParam String username,
                        @RequestParam String password,
                        HttpServletResponse response) {
        try {
            UsernamePasswordAuthenticationToken authToken =
                new UsernamePasswordAuthenticationToken(username, password);
            authenticationManager.authenticate(authToken);

            String token = jwtUtil.generateToken(username);
            response.setHeader("Authorization", "Bearer " + token);
            return "loginSuccess";
        } catch (AuthenticationException e) {
            return "loginError";
        }
    }
}

このように、Spring SecurityのAuthenticationManagerで認証し、JWTを発行する構成が基本となります。発行されたトークンはレスポンスヘッダーに設定され、以後のリクエストで使用可能となります。

6. トークンの保存・利用方法(Cookieやヘッダー)

6. トークンの保存・利用方法(Cookieやヘッダー)
6. トークンの保存・利用方法(Cookieやヘッダー)

JWTトークンは、ログイン後にクライアントに返却されますが、その保存方法にはいくつかの選択肢があります。代表的なのは以下の2つです。

  • HTTPヘッダー(Authorization)に保存
  • Cookieに保存

もっとも一般的なのは、Authorizationヘッダーに保存する方法です。以下のように設定して、リクエストごとにトークンを送信します。


Authorization: Bearer xxxxxx.yyyyy.zzzzz

一方で、Cookieに保存する方法もあります。セキュリティを考慮してHttpOnlySecure属性を使い、JavaScriptからアクセスできないようにするのが推奨されます。


Cookie jwtCookie = new Cookie("jwtToken", token);
jwtCookie.setHttpOnly(true);
jwtCookie.setSecure(true); // HTTPS環境の場合
jwtCookie.setPath("/");
response.addCookie(jwtCookie);

Cookieに保存する場合は、Spring SecurityのフィルターでCookieを取り出して検証する処理を追加する必要があります。

初心者におすすめなのは、まずはAuthorizationヘッダー方式です。扱いがシンプルで、開発やデバッグがしやすいという利点があります。

7. 初心者がつまずきやすいポイントと対策

7. 初心者がつまずきやすいポイントと対策
7. 初心者がつまずきやすいポイントと対策

JWTトークンの発行や認証は一見シンプルに見えますが、初心者がつまずきやすいポイントもいくつかあります。ここでは代表的な例とその対処法を紹介します。

【ケース1:トークンが正しく発行されない】

このエラーは、主にAuthenticationManagerの設定ミスや、ユーザー情報の取得に失敗している場合に発生します。対策として、ユーザー情報の読み込みロジックやAuthenticationProviderの設定を見直しましょう。

【ケース2:トークンを送っても認証されない】

この場合は、Spring Securityのフィルターでトークンの検証処理がうまく動作していない可能性があります。フィルターでAuthorizationヘッダーが正しく取得できているかを確認しましょう。


String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
    String token = authHeader.substring(7);
    // トークンの検証処理へ
}
【ケース3:トークンの有効期限切れ】

JWTには有効期限(exp)があります。開発中に短い時間を設定していた場合、意図せず期限切れになってしまうことがあります。設定値と現在時刻の差を確認しましょう。

【ケース4:署名エラー】

JWTの署名が一致しないと、トークンが改ざんされたとみなされ、認証エラーになります。SECRET_KEYの値が一致しているか確認してください。

こうしたつまずきを減らすためには、エラーメッセージをしっかりログに出力し、JWTライブラリの使い方を正確に把握することが重要です。また、Spring Securityの設定ファイルSecurityFilterChainの記述ミスもトラブルの原因になるため注意が必要です。

初心者が安心して取り組むには、まずはログイン → トークン発行 → ヘッダー送信というシンプルな構成から始め、徐々に拡張していく方法がおすすめです。

コメント
コメント投稿は、ログインしてください

まだ口コミはありません。

カテゴリの一覧へ
新着記事
New1
Spring認証(Spring Security)
ロールベースのアクセス制御を完全解説!@PreAuthorizeと@PostAuthorizeの使い方と違い
New2
SpringのWeb開発(Spring MVC)
Spring MVCの基本構成(Model, View, Controller)を徹底解説!初心者向けガイド
New3
SpringのDB操作
@Column, @Table の設定とデフォルト値を完全ガイド!初心者でもわかるエンティティ設定の基礎
New4
SpringのWeb開発(Spring MVC)
ルーティングとは?基本概念(Spring MVCのURL制御を理解)
人気記事
No.1
Java&Spring記事人気No1
Thymeleaf
Thymeleaf とは?初心者向けにThymeleafの基本を徹底解説
No.2
Java&Spring記事人気No2
Springの基本
Spring Bootの環境変数の設定方法をやさしく解説!初心者向けapplication.propertiesの使い方
No.3
Java&Spring記事人気No3
SpringのDB操作
JPAの標準クエリメソッド(findById, findAll)を完全解説!初心者でもわかるデータ取得の基本
No.4
Java&Spring記事人気No4
Spring認証(Spring Security)
Spring Securityの概要と仕組みを完全ガイド!初心者でもわかるセキュリティ対策
No.5
Java&Spring記事人気No5
Springの基本
application.properties と YAML の基本をやさしく解説!初心者向けSpring Boot設定ファイル入門
No.6
Java&Spring記事人気No6
SpringのWeb開発(Spring MVC)
ルーティングとは?基本概念(Spring MVCのURL制御を理解)
No.7
Java&Spring記事人気No7
SpringのDB操作
@Column, @Table の設定とデフォルト値を完全ガイド!初心者でもわかるエンティティ設定の基礎
No.8
Java&Spring記事人気No8
SpringのAPI開発(REST & GraphQL)
REST APIの主要なHTTPメソッド(GET, POST, PUT, DELETE)を初心者向けにわかりやすく解説!