ASP.NET Core Minimal API アプリで、クライアントから送信されてきた JWT からユーザー名やトークンの有効期限などの Payload 情報(ASP.NET ではそれらがクレーム情報になる)を取得する方法を書きます。

先の記事「Minimal API で JWT を使った認証」に書いた JWT による認証を実装した ASP.NET Core Minimal API アプリでは、普通に Controller を使用した Web API と同様に、上の画像の JWT の Payload 部分は ASP.NET Core で言うクレームのコレクションとして取り扱われます。
先の記事に従って JWT の発行機能を実装すれば、上の画像通り JWT の Payload に exp (Expiration Time), iss (Issuer), aud (Audience) はデフォルトで含まれます。
任意のクレーム情報を追加することも可能です。例えば Admin ロールとユーザーの id を追加する場合は、先の記事に書いた JWT を生成するヘルパメソッド BuildToken で JwtSecurityToken コンストラクタのパラメータ claims に追加する情報を設定します。具体例は以下の通りです。
// JWT を生成するヘルパメソッド
private static string BuildToken(IConfiguration config, string id)
{
var key = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(config["Jwt:Key"]!));
var creds = new SigningCredentials(
key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: config["Jwt:Issuer"],
audience: config["Jwt:Issuer"],
// Admin ロールと id を Claims に追加
claims: [
new Claim(ClaimTypes.Role, "Admin"),
new Claim("UserId", id)
],
notBefore: null,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
}
上の BuildToken メソッドで生成した JWT をデコードしたものがこの記事の一番上の画像で、Payload に Admin ロールと UserId が追加されています。
エンドポイントにおいて JWT からクレーム情報を取得するのは先の記事「JWT からクレーム情報を取得」に書いた方法と同様にして可能です。
ただし、先の記事のアプリでは ControllerBase.User プロパティから ClaimsPrincipal オブジェクトを取得していましたが、Minimal API は Controller を使わないので、そこのところのみ異なります。
Minimal API では、Microsoft のドキュメント「Minimal API クイック リファレンス」の「特殊な型」のセクションに書いてありますように、エンドポイントに設定したデリゲートの引数に ClaimsPrincipal を含めることで取得します。具体例は以下の通りです。
// 認証が必要なエンドポイント
app.MapGet("/todoitems/auth", [Authorize(Roles = "Admin")]
async (TodoDb db, ClaimsPrincipal user) =>
{
// JWT の Payload の情報は以下のようにして取得できる
string? role = user.FindFirst(ClaimTypes.Role)?.Value;
string? userId = user.FindFirst("UserId")?.Value;
string? exp = user.FindFirst("exp")?.Value; // UNIX 時間
if (exp != null)
{
var ticks = long.Parse(exp) * 1000L * 1000L * 10L +
DateTime.UnixEpoch.Ticks;
var expDateTime = new DateTime(ticks, DateTimeKind.Utc);
var dateTimeUtcNow = DateTime.UtcNow;
bool isBeforeExp = expDateTime > dateTimeUtcNow;
}
return Results.Ok(await db.Todos.ToListAsync());
});
クライアントから JWT が送信されてくると、その Payload の情報から ClaimsPrincipal オブジェクトが生成され、上のコードのデリゲートの引数 ClaimsPrincipal user に渡されます。それから FindFirst(String) メソッドを使ってJWT の Payload の情報を取得できます。
下の画像は Visual Studio 2022 のデバッガを使って上のコードのローカル変数の値を表示したものです。JWT はこの記事の一番上の画像のものです。JWT の Payload の role, userId, exp の情報が正しく取得できていることが分かりますでしょうか?
