JWT ペイロードを Java POJO に変換する
標準 JWT クレーム(iss、sub、aud、exp、iat、nbf、jti)とアプリ固有クレームを含む Java POJO を生成します。
Real-world
詳細な説明
Java での JWT ペイロード
JSON Web Token のペイロードは RFC 7519 で定義された標準クレームと、アプリが追加した任意クレームを含む JSON オブジェクトです。
標準的な JWT ペイロード
{
"iss": "https://auth.example.com",
"sub": "user_42",
"aud": "api.example.com",
"exp": 1700000000,
"iat": 1699996400,
"nbf": 1699996400,
"jti": "a1b2c3d4",
"scope": "read:profile write:profile",
"roles": ["admin", "billing"]
}
生成される POJO
package com.example.security;
import java.util.List;
public class JwtPayload {
private String iss; // 発行者
private String sub; // サブジェクト
private String aud; // オーディエンス
private Long exp; // 失効(Unix タイムスタンプ)
private Long iat; // 発行時刻
private Long nbf; // 有効開始時刻
private String jti; // JWT ID
private String scope;
private List<String> roles;
// アクセサ
}
改善ポイント
自動生成 POJO は十分な出発点ですが、本番に持ち込むには 3 つの改善が有効です。
1. タイムスタンプを Instant に変換
public Instant getExpiry() {
return Instant.ofEpochSecond(exp);
}
public boolean isExpired() {
return Instant.now().isAfter(getExpiry());
}
2. aud を String OR List として扱う
JWT 仕様では aud は単一文字列でも配列でも構いません。カスタム Jackson デシリアライザを書くか、@JsonDeserialize(using = AudienceDeserializer.class) で両方をモデル化します。
3. カスタムクレームは Map に集約
標準クレーム以外にアプリ独自フィールドが付くなら次のように受け取れます。
@JsonAnyGetter @JsonAnySetter
private Map<String, Object> customClaims = new HashMap<>();
@JsonAnyGetter と @JsonAnySetter により、未知キーが自動的に Map にルーティングされます。
検証済みトークンの扱い
java-jwt、nimbus-jose-jwt、jjwt などの JWT ライブラリで署名を先に検証し、その後でクレームを POJO にマッピングします。
DecodedJWT jwt = JWT.require(Algorithm.RSA256(publicKey, null))
.build()
.verify(token);
ObjectMapper mapper = new ObjectMapper();
JwtPayload payload = mapper.readValue(jwt.getPayload(), JwtPayload.class);
検査用デコード
認証ではなくクレームを覗き見たいだけなら、JWT デコーダー でブラウザ内検証してから POJO 生成に進むと便利です。
ユースケース
認証ミドルウェア、カスタムクレームの抽出、監査ログのいずれにおいても、型付きの JWT ペイロードクラスは有効です。Spring Security、Quarkus Security、Micronaut Security のいずれもカスタム POJO へのデシリアライズに対応できます。