mcpField
S
spring-boot-security-jwt

spring-boot-security-jwt

github.com/giuseppe-trisciuoglioセキュリティ3654.1k 回インストール7 週間前に更新
リポジトリ

spring-boot-security-jwt について

Spring Boot 開発者向けの JWT セキュリティ実装スキルです。ステートレス認証、トークンローテーション、細かな認可のパターンを扱い、Spring Security 6.x と JJWT を対象とします。

主な機能

  1. 01アクセストークンとリフレッシュトークンの生成・検証
  2. 02Bearer と HttpOnly Cookie による認証
  3. 03リフレッシュトークンのローテーション、失効、ブラックリスト化
  4. 04ロール・権限ベースの認可
  5. 05OAuth2 連携とセキュリティテスト

活用シーン

  1. 01REST API への JWT 認証追加
  2. 02ログイン、更新、ログアウト処理の実装
  3. 03ロールまたは権限によるアクセス制御の設定
  4. 04Spring Security 設定のテスト

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill spring-boot-security-jwt

インストール後、Claude Code で/spring-boot-security-jwtを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/
generate-jwt-keys.sh
references/
authorization-patterns.md
configuration.md
examples.md
jwt-complete-configuration.md
jwt-configuration.md
jwt-quick-reference.md
jwt-testing-guide.md
microservices-security.md
migration-spring-security-6x.md
oauth2-integration.md
performance-optimization.md
security-hardening.md
structure.md
testing-jwt-security.md
testing.md
token-management.md
troubleshooting.md
scripts/
test-jwt-setup.sh

詳細

Spring Boot JWT Security

Spring Security 6.x と JJWT を使用した Spring Boot 3.5.x 向けの JWT 認証・認可パターンです。トークンの生成、検証、更新戦略、RBAC/ABAC、OAuth2 連携について説明します。

概要

このスキルでは、Spring Boot アプリケーションでステートレスな JWT 認証を実装するためのパターンを紹介します。JJWT 0.12.6 によるトークン生成、Bearer/Cookie ベースの認証、リフレッシュトークンのローテーション、@PreAuthorize 式を使ったメソッドレベルの認可など、認証フロー全体を扱います。

主な機能:

  • 有効期限を設定できるアクセストークンとリフレッシュトークンの生成
  • Bearer トークンおよび HttpOnly Cookie による認証方式
  • Spring Data JPA および OAuth2 プロバイダーとの連携
  • ロール/権限ベースの @PreAuthorize ルールによる RBAC
  • ログアウト/ローテーション時のトークン失効とブラックリスト登録

使用する場面

ユーザーから次のような依頼があった場合に有効化します:

  • 「JWT 認証を実装して」「トークンで REST API を保護して」
  • 「Spring Security 6.x の設定」「SecurityFilterChain の設定」
  • 「ロールベースのアクセス制御」「RBAC」`@PreAuthorize`
  • 「リフレッシュトークン」「トークンのローテーション」「トークンの失効」
  • 「OAuth2 連携」「ソーシャルログイン」「Google/GitHub 認証」
  • 「ステートレス認証」「SPA バックエンドのセキュリティ」
  • 「JWT フィルター」「OncePerRequestFilter」「Bearer トークン」
  • 「Cookie ベースの JWT」「HttpOnly Cookie」
  • 「権限ベースのアクセス制御」「カスタム PermissionEvaluator」

クイックリファレンス

依存関係(JJWT 0.12.6)
成果物スコープ
spring-boot-starter-securityコンパイル
spring-boot-starter-oauth2-resource-serverコンパイル
io.jsonwebtoken:jjwt-api:0.12.6コンパイル
io.jsonwebtoken:jjwt-impl:0.12.6実行時
io.jsonwebtoken:jjwt-jackson:0.12.6実行時
spring-security-testテスト

Maven と Gradle の記述例については、references/jwt-quick-reference.md を参照してください。

主な設定プロパティ
プロパティ設定例備考
jwt.secret${JWT_SECRET}最小 256 ビット。ハードコードしないでください
jwt.access-token-expiration900000ミリ秒単位で 15 分
jwt.refresh-token-expiration604800000ミリ秒単位で 7 日
jwt.issuermy-appすべてのトークンで検証されます
jwt.cookie-namejwt-tokenCookie ベースの認証用
jwt.cookie-http-onlytrue本番環境では常に true
jwt.cookie-securetrueHTTPS 使用時は常に true
認可アノテーション
アノテーション例
@PreAuthorize("hasRole('ADMIN')")ロールの確認
@PreAuthorize("hasAuthority('USER_READ')")権限の確認
@PreAuthorize("hasPermission(#id, 'Doc', 'READ')")ドメインオブジェクトの確認
@PreAuthorize("@myService.canAccess(#id)")Spring Bean の確認

手順

ステップ 1 — 依存関係を追加する

ビルドファイルに spring-boot-starter-security、spring-boot-starter-oauth2-resource-server、および JJWT の 3 つの成果物を含めます。Maven/Gradle の正確な記述例については、references/jwt-quick-reference.md を参照してください。

ステップ 2 — application.yml を設定する
jwt:
  secret: ${JWT_SECRET:change-me-min-32-chars-in-production}
  access-token-expiration: 900000
  refresh-token-expiration: 604800000
  issuer: my-app
  cookie-name: jwt-token
  cookie-http-only: true
  cookie-secure: false   # true in production

プロパティの全リファレンスについては、references/jwt-complete-configuration.md を参照してください。

ステップ 3 — JwtService を実装する

主な処理:アクセストークンの生成、リフレッシュトークンの生成、ユーザー名の抽出、トークンの検証。

@Service
public class JwtService {

    public String generateAccessToken(UserDetails userDetails) {
        return Jwts.builder()
            .subject(userDetails.getUsername())
            .issuer(issuer)
            .issuedAt(new Date())
            .expiration(new Date(System.currentTimeMillis() + accessTokenExpiration))
            .claim("authorities", getAuthorities(userDetails))
            .signWith(getSigningKey())
            .compact();
    }

    public boolean isTokenValid(String token, UserDetails userDetails) {
        try {
            String username = extractUsername(token);
            return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
        } catch (JwtException e) {
            return false;
        }
    }
}

鍵管理とクレーム抽出を含む JwtService の完全な実装については、references/jwt-complete-configuration.md を参照してください。

ステップ 4 — JwtAuthenticationFilter を作成する

OncePerRequestFilter を拡張して、Authorization: Bearer ヘッダー(または HttpOnly Cookie)から JWT を抽出し、検証してから SecurityContext に設定します。

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            chain.doFilter(request, response);
            return;
        }
        String jwt = authHeader.substring(7);
        String username = jwtService.extractUsername(jwt);
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            if (jwtService.isTokenValid(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken authToken =
                    new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        }
        chain.doFilter(request, response);
    }
}

Cookie ベースの実装については、references/configuration.md を参照してください。

ステップ 5 — SecurityFilterChain を設定する
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http
            .csrf(AbstractHttpConfigurer::disable)
            .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**", "/swagger-ui/**").permitAll()
                .anyRequest().authenticated()
            )
            .authenticationProvider(authenticationProvider)
            .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
            .build();
    }
}

CORS、ログアウトハンドラー、OAuth2 ログインの統合については、references/jwt-complete-configuration.md を参照してください。

ステップ 6 — 認証エンドポイントを作成する

@RestController を介して /register、/authenticate、/refresh、/logout を公開します。レスポンスボディで accessToken と refreshToken を返します(必要に応じて HttpOnly Cookie も設定します)。

AuthenticationController と AuthenticationService の完全な実装については、references/examples.md を参照してください。

ステップ 7 — リフレッシュトークン戦略を実装する

user_id、expiry_date、revoked、expired の各列を含むリフレッシュトークンをデータベースに保存します。/refresh では、保存されているトークンを検証して無効化し、新しいトークンのペアを発行します(トークンローテーション)。

RefreshToken エンティティ、ローテーションのロジック、Redis ベースのブラックリスト化については、references/token-management.md を参照してください。

ステップ 8 — 認可ルールを追加する

細かな制御には、@EnableMethodSecurity と @PreAuthorize アノテーションを使用します。

@PreAuthorize("hasRole('ADMIN')")
public Page<UserResponse> getAllUsers(Pageable pageable) { ... }

@PreAuthorize("hasPermission(#documentId, 'Document', 'READ')")
public Document getDocument(Long documentId) { ... }

RBAC エンティティモデル、PermissionEvaluator、ABAC パターンについては、references/authorization-patterns.md を参照してください。

ステップ 9 — セキュリティテストを作成する
@SpringBootTest
@AutoConfigureMockMvc
class AuthControllerTest {

    @Test
    void shouldDenyAccessWithoutToken() throws Exception {
        mockMvc.perform(get("/api/orders"))
            .andExpect(status().isUnauthorized());
    }

    @Test
    @WithMockUser(roles = "ADMIN")
    void shouldAllowAdminAccess() throws Exception {
        mockMvc.perform(get("/api/admin/users"))
            .andExpect(status().isOk());
    }
}

テストスイート一式、Testcontainers のセットアップ、セキュリティテストのチェックリストについては、references/testing.md と references/jwt-testing-guide.md を参照してください。

ベストプラクティス

トークンのセキュリティ
  • 最低 256 ビットの秘密鍵を使用します。環境変数から読み込み、ハードコードしないでください
  • アクセストークンの有効期間は短く設定します(15 分)。長時間のセッションにはリフレッシュトークンを使用します
  • トークンローテーションを実装します。新しいリフレッシュトークンを発行する際は、古いリフレッシュトークンを無効化します
  • ログアウト時のブラックリスト化には jti(JWT ID)クレームを使用します
Cookie と Bearer ヘッダー
  • ブラウザクライアントには HttpOnly Cookie を優先します(XSS 対策)
  • モバイル/API クライアントには Authorization: Bearer ヘッダーを使用します
  • 本番環境では Cookie に Secure と SameSite=Lax または Strict を設定します
Spring Security 6.x
  • SecurityFilterChain Bean を使用し、WebSecurityConfigurerAdapter は決して継承しないでください
  • CSRF を無効にするのはステートレス API の場合に限ります。セッションベースのフローでは有効にしておきます
  • 非推奨の @EnableGlobalMethodSecurity ではなく、@EnableMethodSecurity を使用します
  • iss と aud のクレームを検証し、信頼できない発行者のトークンを拒否します
パフォーマンス
  • リクエストごとの DB 検索を避けるため、@Cacheable で UserDetails をキャッシュします
  • 署名鍵の導出をキャッシュします(リクエストごとに HMAC 鍵を再計算しないでください)
  • 大規模運用では、リフレッシュトークンの保存に Redis を使用します
してはいけないこと
  • JWT クレームに機密データ(パスワード、PII)を保存しないでください。クレームは署名されるだけで、暗号化はされません
  • 有効期間が無期限のトークンを発行しないでください
  • 署名と有効期限を検証せずにトークンを受け入れないでください
  • 環境間で署名鍵を共有しないでください

例

基本的な認証フロー
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {

    private final AuthService authService;

    @PostMapping("/authenticate")
    public ResponseEntity<AuthResponse> authenticate(
            @RequestBody LoginRequest request) {
        return ResponseEntity.ok(authService.authenticate(request));
    }

    @PostMapping("/refresh")
    public ResponseEntity<AuthResponse> refresh(@RequestBody RefreshRequest request) {
        return ResponseEntity.ok(authService.refreshToken(request.refreshToken()));
    }

    @PostMapping("/logout")
    public ResponseEntity<Void> logout() {
        authService.logout();
        return ResponseEntity.ok().build();
    }
}
コントローラーメソッドでの JWT 認可
@RestController
@RequestMapping("/api/admin")
@PreAuthorize("hasRole('ADMIN')")
public class AdminController {

    @GetMapping("/users")
    public ResponseEntity<List<UserResponse>> getAllUsers() {
        return ResponseEntity.ok(adminService.getAllUsers());
    }
}

エンティティモデルとサービス実装の完全な例については、references/examples.md を参照してください。

参考資料

ファイル内容
references/jwt-quick-reference.md依存関係、最小構成のサービス、一般的なパターン
references/jwt-complete-configuration.md完全な設定:プロパティ、SecurityFilterChain、JwtService、OAuth2 RS
references/configuration.mdJWT 設定 Bean、CORS、CSRF、エラー処理、セッションオプション
references/examples.mdアプリケーションの完全なセットアップ:コントローラー、サービス、エンティティ
references/authorization-patterns.mdRBAC/ABAC エンティティモデル、PermissionEvaluator、SpEL 式
references/token-management.mdリフレッシュトークンのエンティティ、ローテーション、Redis によるブラックリスト化
references/testing.mdユニットテストと MockMvc テスト、テストユーティリティ
references/jwt-testing-guide.mdTestcontainers、負荷テスト、セキュリティテストのチェックリスト
references/security-hardening.mdセキュリティヘッダー、HSTS、レート制限、監査ログ
references/performance-optimization.mdCaffeine キャッシュ設定、非同期検証、コネクションプーリング
references/oauth2-integration.mdGoogle/GitHub OAuth2 ログイン、OAuth2UserService
references/microservices-security.mdサービス間の JWT 伝播、リソースサーバー設定
references/migration-spring-security-6x.mdSpring Security 5.x からの移行
references/troubleshooting.md一般的なエラー、デバッグのヒント

制約と警告

セキュリティ上の制約
  • JWT トークンは署名されていますが、暗号化されていません。クレームに機密データを含めないでください
  • トークンを信頼する前に、必ず exp、iss、aud クレームを検証してください
  • 署名キーは 256 ビット以上である必要があります。本番環境では決して脆弱なキーを使用しないでください
  • シークレットは環境変数またはセキュアな Vault から読み込み、設定ファイルから読み込まないでください
  • Cookie ベースのフローで CSRF を防ぐには、SameSite Cookie 属性が不可欠です
Spring Security 6.x の制約
  • WebSecurityConfigurerAdapter は削除されました。SecurityFilterChain Bean のみを使用してください
  • @EnableGlobalMethodSecurity は非推奨です。@EnableMethodSecurity を使用してください
  • HttpSecurity の設定には Lambda DSL が必須です(メソッドチェーンは使用できません)
  • WebSecurityConfigurerAdapter.order() は、@Configuration クラスに付与する @Order に置き換えられました
トークンの制約
  • セキュリティのため、アクセストークンの有効期限は 5~15 分に設定してください
  • リフレッシュトークンはサーバー側(DB または Redis)に保存し、localStorage には保存しないでください
  • ログアウト時に即時失効できるよう、トークンのブラックリスト化を実装してください
  • トークンのブラックリスト化を正しく機能させるには、jti クレームが必要です

関連スキル

  • spring-boot-dependency-injection — 全体で使用するコンストラクターインジェクションのパターン
  • spring-boot-rest-api-standards — REST API のセキュリティパターンとエラー処理
  • unit-test-security-authorization — Spring Security 設定のテスト
  • spring-data-jpa — ユーザーエンティティとリポジトリーのパターン
  • spring-boot-actuator — セキュリティ監視とヘルスエンドポイント

コメント