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

JWTの認証フィルターを作成する方法|Spring Securityでの実装手順を初心者向けに解説!

JWTの認証フィルターを作成する方法
JWTの認証フィルターを作成する方法

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

新人

「Spring SecurityでJWTを使った認証をやりたいんですけど、認証フィルターって何をするんですか?」

先輩

「認証フィルターは、ログイン済みかどうかをチェックするゲートみたいな役割だよ。JWTを使う場合は、このフィルターでトークンを検証してから処理を進めるんだ。」

新人

「なるほど、トークンの中身を確認してユーザーが誰かを判断してるんですね。実装も難しそう…」

先輩

「確かに初めてだと戸惑うかも。でも一つずつ理解していけば、Spring SecurityのJWT認証フィルターの仕組みはそんなに難しくないよ!」

1. JWT認証フィルターとは何か?

1. JWT認証フィルターとは何か?
1. JWT認証フィルターとは何か?

Spring SecurityでのJWT認証フィルターとは、リクエストに含まれるJWTトークンを検査し、正しいユーザー情報かどうかを確認する役割を担う重要なコンポーネントです。セッション方式とは異なり、トークンベースの認証では各リクエストごとに検証が行われるため、ステートレスなAPI設計に向いています。

JWTフィルターの主な処理は次の通りです:

  • リクエストのAuthorizationヘッダーからJWTトークンを取得
  • トークンが正しく署名されているか、有効期限内かを検証
  • ユーザー情報を取得し、Spring Securityの認証オブジェクトとしてセット

これにより、各リクエストごとに「そのユーザーが本当にログイン済みかどうか」を安全にチェックできます。

特に「Spring Security JWT 認証フィルター」というキーワードで調べる人が多く、実装例や手順をわかりやすく解説することが初心者にとって非常に重要です。

2. 認証フィルターの基本的な役割とJWTの関係

2. 認証フィルターの基本的な役割とJWTの関係
2. 認証フィルターの基本的な役割とJWTの関係

Spring Securityでは、すべてのリクエストが一連の「フィルター」を通過します。その中に自作のJWT認証フィルターを追加することで、トークンによる認証処理を独自にカスタマイズできます。JWTフィルターは、そのリクエストが保護されたリソースにアクセスする前に、認証されているかどうかを確認するチェックポイントです。

JWTを使った認証フィルターの中でよく使われるのが、Spring SecurityのOncePerRequestFilterクラスを継承する方法です。名前の通り、リクエストごとに一度だけ実行されるフィルターで、ここでJWTの検証やユーザー情報の設定が行えます。

以下は、JWTフィルター作り方としてよく紹介される基本構成のサンプルです:


public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtUtil jwtUtil;

    public JwtAuthenticationFilter(JwtUtil jwtUtil) {
        this.jwtUtil = jwtUtil;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            String username = jwtUtil.extractUsername(token);
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UsernamePasswordAuthenticationToken authentication =
                    new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
        filterChain.doFilter(request, response);
    }
}

このコードでは、JWTをヘッダーから取り出し、有効であればSpring Securityにユーザーとして認識させています。認証済みユーザーとして扱われることで、コントローラーなどで@PreAuthorizehasRole()などの認可機能が使えるようになります。

また、このフィルターをどのようにSecurityFilterChainに登録するかが、次のステップで重要になりますが、それは中盤の記事で詳しく紹介します。

初心者の方は、JWTと認証フィルターの関係をしっかり押さえておくことで、Spring SecurityでのJWT認証の流れを理解しやすくなります。

3. フィルタークラスの作成方法(OncePerRequestFilterを継承)

3. フィルタークラスの作成方法(OncePerRequestFilterを継承)
3. フィルタークラスの作成方法(OncePerRequestFilterを継承)

Spring Security Filter JWTを実装する際の第一歩は、OncePerRequestFilterを継承したクラスを作成することです。OncePerRequestFilterは、名前の通り、リクエストごとに一度だけ実行されるフィルターです。

このカスタムフィルターを作ることで、JWTトークンの抽出や検証、Spring Securityコンテキストへの認証情報の登録などを行うことができます。以下に、JWT 認証フィルター 実装の基本形を示します。


public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtUtil jwtUtil;

    public JwtAuthenticationFilter(JwtUtil jwtUtil) {
        this.jwtUtil = jwtUtil;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        String token = extractToken(request);

        if (token != null && jwtUtil.validateToken(token)) {
            String username = jwtUtil.extractUsername(token);
            UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        filterChain.doFilter(request, response);
    }

    private String extractToken(HttpServletRequest request) {
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            return authHeader.substring(7);
        }
        return null;
    }
}

上記のように、JWTトークンの抽出処理を専用のメソッドに分けることで、コードの見通しが良くなります。また、トークンの検証処理は後述するjwtUtil.validateTokenメソッドに委ねています。

4. JWTトークンの検証処理の実装(ユーザー情報の抽出、エラー処理など)

4. JWTトークンの検証処理の実装(ユーザー情報の抽出、エラー処理など)
4. JWTトークンの検証処理の実装(ユーザー情報の抽出、エラー処理など)

次に、JWTトークンの検証とユーザー情報の抽出を行う処理を実装します。この処理は通常、JwtUtilのようなユーティリティクラスにまとめておきます。

JWTのトークンは署名付きで生成されており、トークンを受け取った側ではこの署名の正当性や有効期限などを検証する必要があります。

以下はJwtUtilクラスの例です。


@Component
public class JwtUtil {

    private final String secretKey = "my-secret-key";

    public String extractUsername(String token) {
        return getClaims(token).getSubject();
    }

    public boolean validateToken(String token) {
        try {
            Claims claims = getClaims(token);
            return !claims.getExpiration().before(new Date());
        } catch (Exception e) {
            return false;
        }
    }

    private Claims getClaims(String token) {
        return Jwts.parser()
                   .setSigningKey(secretKey)
                   .parseClaimsJws(token)
                   .getBody();
    }
}

このクラスでは、トークンの署名と有効期限を検証し、問題がなければユーザー名(サブジェクト)を取得します。トークンが改ざんされていたり、有効期限を過ぎていた場合は例外が発生し、falseを返す仕組みです。

このようにJwtUtilを使えば、JWT 認証フィルター 実装の際に複雑な処理を簡潔にまとめられます。

5. SecurityFilterChainへの組み込み方法(Bean登録)

5. SecurityFilterChainへの組み込み方法(Bean登録)
5. SecurityFilterChainへの組み込み方法(Bean登録)

作成したJwtAuthenticationFilterSpring Securityの認証フローに組み込むには、SecurityFilterChainの設定が必要です。SecurityFilterChainは、Spring Security 5.7以降で推奨されているセキュリティ設定の方法です。

以下は、フィルターを登録する方法の一例です。


@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private JwtUtil jwtUtil;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeHttpRequests()
                .requestMatchers("/login", "/register").permitAll()
                .anyRequest().authenticated()
            .and()
            .addFilterBefore(new JwtAuthenticationFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
}

.addFilterBefore()メソッドを使って、UsernamePasswordAuthenticationFilterの前にJwtAuthenticationFilterを追加することで、トークンの検証が認証処理の前に行われるようになります。

これにより、リクエストがSpring Securityに到達する前にJWTトークンがチェックされ、認証済みかどうかの判定が可能になります。

以上のステップで、Spring Security Filter JWTの設定は完了です。自作したJWT認証フィルターがセキュリティ機能の一部として動作するようになり、ログイン不要のAPIと認証必須のAPIを安全に分けて運用できます。

6. 認証フィルターが動作する流れの確認(リクエスト〜認証処理まで)

6. 認証フィルターが動作する流れの確認(リクエスト〜認証処理まで)
6. 認証フィルターが動作する流れの確認(リクエスト〜認証処理まで)

Spring Security フィルター 順序を理解することは、JWT認証が正しく動作するために非常に重要です。では実際に、リクエストから認証処理が完了するまでの流れを確認してみましょう。

1つのリクエストがWebアプリケーションに届いたとき、最初に通過するのがSpring Securityのフィルターチェーンです。その中で自作したJwtAuthenticationFilterは、UsernamePasswordAuthenticationFilterの前に挿入されているため、パスワード認証処理よりも前にJWTトークンの検証が行われます。

フィルターの内部では、以下のような流れで処理が進みます:

  • ① リクエストヘッダーに含まれるAuthorizationからBearerトークンを取得
  • JwtUtilを使ってトークンの有効性を確認(署名や有効期限など)
  • ③ トークンに含まれるユーザー情報を取り出し、Authenticationオブジェクトを生成
  • ④ セキュリティコンテキストに認証情報をセット

このようにして認証が完了すると、後続の処理やコントローラーではそのユーザーがログイン済みとして扱われるようになります。

つまり、JWT 認証フィルター 実装の効果が、リクエストごとに確実に働くというわけです。

7. よくあるエラーとその対策(NullPointerException、トークン無効など)

7. よくあるエラーとその対策(NullPointerException、トークン無効など)
7. よくあるエラーとその対策(NullPointerException、トークン無効など)

JWT認証フィルターを導入すると、実装初期にいくつかのエラーに遭遇することがあります。ここではNullPointerExceptionやトークンの不正など、初心者がつまずきやすい問題とその解決策を紹介します。

① NullPointerExceptionが発生する

よくある原因は、JWTトークンがリクエストに含まれていないにもかかわらず、そのトークンから情報を取得しようとしているケースです。以下のように、nullチェックを入れておくことで防げます。


String token = extractToken(request);
if (token != null && jwtUtil.validateToken(token)) {
    // 認証処理を実行
}

また、SecurityContextHolderへのアクセス時もnullチェックを忘れないようにしましょう。安全に扱うことがセキュリティ上も大切です。

② JWTトークンが無効と判定される

JWT 認証 エラー 対処法」として代表的なのが、有効期限切れや署名不一致などによるトークンエラーです。

その場合は、JwtUtilの中で例外を明確にキャッチし、ログに記録するなどの処理を追加しましょう。


public boolean validateToken(String token) {
    try {
        Claims claims = getClaims(token);
        return !claims.getExpiration().before(new Date());
    } catch (ExpiredJwtException e) {
        System.out.println("トークンの有効期限切れ");
    } catch (SignatureException e) {
        System.out.println("署名が無効です");
    } catch (Exception e) {
        System.out.println("トークンの検証に失敗しました");
    }
    return false;
}

このように詳細なエラーメッセージを出すことで、問題の切り分けがしやすくなります。

③ フィルターが通っていない

フィルターが機能していない原因の多くは、Spring Security フィルター 順序の設定ミスです。.addFilterBefore()の位置が適切かどうかを見直しましょう。

UsernamePasswordAuthenticationFilterの「前」に自作のJWT認証フィルターを追加するのが正解です。


.addFilterBefore(new JwtAuthenticationFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class)

ここを間違えると、認証がスキップされるため注意しましょう。

8. 初心者におすすめの学習手順(JWT認証処理の習得ステップ)

8. 初心者におすすめの学習手順(JWT認証処理の習得ステップ)
8. 初心者におすすめの学習手順(JWT認証処理の習得ステップ)

最後に、JWTを使った認証処理を段階的に学ぶためのステップを紹介します。最初から全部を理解しようとせず、1つずつ丁寧に進めることが大切です。

ステップ①:Spring Securityの基本を理解

まずはSpring Securityの仕組みを把握しましょう。セキュリティチェーンやAuthenticationSecurityContextの役割を学ぶことで、JWT認証の全体像が見えてきます。

ステップ②:JWTの構造と生成方法を学ぶ

JWTは3つのパート(ヘッダー・ペイロード・署名)から構成されており、それぞれの意味やトークンの生成方法を理解することが重要です。自作のJwtUtilクラスを使ってトークンを生成・検証する練習をしましょう。

ステップ③:フィルターのカスタマイズに挑戦

Spring Security Filter JWTのカスタマイズでは、OncePerRequestFilterの継承や、SecurityFilterChainへの組み込みがポイントです。動作確認やログ出力を交えながら、処理の流れを追ってみてください。

ステップ④:認可機能との連携を試す

最後に、取得した認証情報を使って、@PreAuthorizehasRole()などの認可アノテーションと連携させてみましょう。セキュリティの実用的な部分が見えてきます。

このようにステップごとに取り組むことで、初心者でも確実にJWT 認証フィルター 実装を習得できます。焦らずじっくり進めていきましょう。

この記事を読んだ人からの質問

この記事を読んだ人からの質問
この記事を読んだ人からの質問

プログラミング初心者からのよくある疑問/質問を解決します

JWT認証フィルターとは何ですか?Spring Securityでの役割は?

JWT認証フィルターとは、HTTPリクエストに含まれるJWTトークンを検証して、ユーザーが正しいかどうかを確認するSpring Securityの重要なコンポーネントです。セッションを使わないステートレスなAPI設計に適しており、毎回のリクエストでトークンの有効性をチェックします。
コメント
コメント投稿は、ログインしてください

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

カテゴリの一覧へ
新着記事
New1
Thymeleaf
Thymeleaf JavaScriptで変数を扱う方法を完全ガイド!初心者でもわかる基本と活用
New2
Thymeleaf
Thymeleaf if elseの書き方と条件分岐の活用法!初心者でもわかる使いこなしガイド
New3
Spring認証(Spring Security)
Spring BootでOAuth2を導入する方法を完全解説!初心者向けステップバイステップガイド
New4
Spring認証(Spring Security)
Spring Securityのデフォルトログインフォームとそのカスタマイズ方法を初心者向けに解説!
人気記事
No.1
Java&Spring記事人気No1
Thymeleaf
Thymeleaf とは?初心者向けにThymeleafの基本を徹底解説
No.2
Java&Spring記事人気No2
SpringのWeb開発(Spring MVC)
ルーティングとは?基本概念(Spring MVCのURL制御を理解)
No.3
Java&Spring記事人気No3
Springの基本
Spring Bootの環境変数の設定方法をやさしく解説!初心者向けapplication.propertiesの使い方
No.4
Java&Spring記事人気No4
SpringのDB操作
JPAの標準クエリメソッド(findById, findAll)を完全解説!初心者でもわかるデータ取得の基本
No.5
Java&Spring記事人気No5
Springの基本
application.properties と YAML の基本をやさしく解説!初心者向けSpring Boot設定ファイル入門
No.6
Java&Spring記事人気No6
SpringのAPI開発(REST & GraphQL)
REST APIの主要なHTTPメソッド(GET, POST, PUT, DELETE)を初心者向けにわかりやすく解説!
No.7
Java&Spring記事人気No7
Spring認証(Spring Security)
セッション管理の基本(@SessionAttributes)を完全解説!初心者でもわかるセッションの仕組み
No.8
Java&Spring記事人気No8
Springの基本
Spring Bootのデフォルトログ設定を徹底解説(Logback / SLF4J)