.NET CoreのJWT認証メモ
Jwtを使った認証周りのメモです。主にソースです。
認証そのもののメモはこちら
調べたバージョンはASP.NET Core 3.1
使い方については他で検索したら出てくるのでここでは詳しく書きません。
パッケージの準備
Microsoft.AspNetCore.Authentication.JwtBearer
を追加します。
バージョンは3.1.4
を使用しました。
コードのメモ
こんな感じで使います。
public void ConfigureServices(IServiceCollection services)
{
//中略
services.
AddAuthentication(option =>
{
option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(option =>
{
//JwtSecurityTokenHandler.ValidateTokenPayloadを通すためにいろいろいるみたい。
//検証はMicrosoft.IdentityModel.Tokens.Validatorsっていう静的クラスがある
//audienceの検証
option.TokenValidationParameters.ValidAudiences = new string[] { "sandbox" };
//issuerの検証
option.TokenValidationParameters.ValidIssuers = new string[] { "epsilon" };
//デフォルトは5分になってて、期限過ぎてもしばらくは検証を合格してしまう。
option.TokenValidationParameters.ClockSkew = TimeSpan.Zero;
//とりあえずテキトーな鍵
byte[] key = Encoding.UTF8.GetBytes("1234567890123456");
SymmetricSecurityKey securityKey = new SymmetricSecurityKey(key);
option.TokenValidationParameters.IssuerSigningKey = securityKey;
});
}
発行側
//payloadに含めるクレーム一覧
List<Claim> claims = new List<Claim>
{
new Claim(ClaimTypes.Name, "Taro")
};
ClaimsIdentity claimsIdentity = new ClaimsIdentity(claims);
//署名用のキー
//TokenValidationParameters.RequireSignedTokensをfalseにすれば、署名なしでも使用可能になるがセキュリティ的にダメ
byte[] key = Encoding.UTF8.GetBytes("1234567890123456");
SymmetricSecurityKey securityKey = new SymmetricSecurityKey(key);
SigningCredentials cred = new SigningCredentials(securityKey, "HS256");
JwtSecurityTokenHandler th = new JwtSecurityTokenHandler();
JwtSecurityToken jst = th.CreateJwtSecurityToken(
issuer: "epsilon",
audience: "sandbox",
subject: claimsIdentity,
notBefore: null,//nullのときは現在時刻が使われるようだ
expires: DateTime.Now.AddMinutes(5),//とりあえず短め
issuedAt: null,//nullのときは現在時刻が使われるようだ
signingCredentials: cred
);
//このtokenをクライアントに返す
string token = th.WriteToken(jst);
登場するクラスメモ
依存しているSystem.IdentityModel.Tokens.Jwt
はAzureAD
側で管理されているようだ
リポジトリはこちら
JwtBearerHandler
ソースはこちら
認証周りのポイントであるIAuthenticationHandler
のJwtの場合の実装クラスです。
- SingIn
- SingOut
は実装されていないのでトークンの発行はHttpContext
経由ではなく自身で行う必要があります。
HandleAuthenticateAsync
メソッド
認証情報を取り出している部分です。
イベントのMessageReceived
を経由することでAuthorization
ヘッダー以外からでもトークンを取り出すことができるようです。(ajaxではなくformをsubmitするような場合に使うのかな?)
イベントのリスナー登録は JwtBearerOptions
から可能なはず。(試していません。)
Authorization
ヘッダーが存在した場合、Bearer
以降の文字列をトークンとして扱うようです。
もしトークンが取得できなかった場合は認証情報を復元しないようです。
その後はトークンの検証が行われます。検証についてのバリデーションの設定はJwtBearerOptions.SecurityTokenValidators で行います。
デフォルトではJwtSecurityTokenHandler
のみがセットされています。
JwtSecurityTokenHandler
ソースはここ
ポイントとなるクラスかなと個人的には思っています。
-
JwtBearerHandler
からは 検証、復元のためにValidateToken
メソッドが呼ばれています。 - トークンの生成のためには
CreateJwtSecurityToken
,WriteToken
などを使用します。
ValidateToken
メソッド
トークンの検証およびClaimsPrincipal
の返却を行います。
トークンをピリオドで分割した後のパート数によってJWE
かどうかの判別をしているようです。
署名部分の検証をValidateSignature
で行い、ペイロード部分の復元、検証をValidateTokenPayload
で行っています。
ValidateTokenPayload では文字通りペイロード部分の検証を行います
多くのものはValidatorsクラスのstaticメソッドに処理を委譲しています。
また検証の際のオプションはJwtBearerOptions.TokenValidationParameters
で設定することができます。
CreateJwtSecurityToken
メソッド
JwtSecurityToken
を作るためのメソッドです。
いくつかオーバーロードされているので使いたいものを選べばよいと思います。
SigningCredentials
を省略した場合、署名なしのトークンが作られますが、さすがにそれはセキュリティ的にアウトだと思います。
まだ私もどれが適切なのか判断できていません。
これ以外にもトークンを作るメソッドはあります。
WriteToken
メソッド
JwtSecurityToken
をstring
にするためのメソッド
TokenValidationParameters
ソースはこちら
トークンの検証/復元において
- 検証そのものの有効化/無効化
- 「有効な値」と判断するものの設定
などをすることができます。
一部の物しか試せていませんが一つだけ紹介します。
ClockSkew
プロパティ
TimeSpan
型のプロパティでデフォルトは5分に設定されています。
Validators.ValidateLifetimeメソッドで使用されており
時間計算の際に時刻をずらすために使われているようです。
なので例えばexpires
の時間を過ぎてもすぐにはトークンは無効とはならず。このClockSkew
の期間だけ猶予があるようです。
終わりに
他にもたくさんのクラスが用意されているので、まだまだいろいろすることができそうです。
MSのドキュメントが見当たらないのでもしよければコメントで教えてください。