大まかな流れ
- AzureAdB2Cのopenid-configurationから関連するEndpointを取得する
- jwks_uriの情報から公開鍵を生成する
- JWTのアクセストークンを検証する
Endpointの取得
必要そうなのは、issuerとjwks_uri
Microosftのサンプルサイト
class OpenIdConfig
{
public string issuer { get; set; }
public string jwks_uri { get; set; }
}
private async Task<OpenIdConfig> GetEndPointAsync(string onfigureEndpointUrl)
{
var result = await _httpClient.GetStringAsync(configureEndpointUrl);
return JsonSerializer.Deserialize<OpenIdConfig>(result);
}
jwks_Uriから公開鍵の生成
private async Task<Dictionary<string, RsaSecurityKey>> GetPublicKeyAsync(string jwksUri)
{
//公開鍵キー情報を復元
var jsonStr = await _httpClient.GetStringAsync(jwksUri);
var sets = new JsonWebKeySet(jsonStr);
//公開鍵生成(jwksUriには複数登録されているためDictionaryとする)
var rsaProvider = new RSACryptoServiceProvider();
var publicKeys = new Dictionary<string, RsaSecurityKey>();
foreach (var key in sets.Keys)
{
rsaProvider.ImportParameters(new RSAParameters
{
Exponent = Base64UrlEncoder.DecodeBytes(key.E),
Modulus = Base64UrlEncoder.DecodeBytes(key.N)
});
publicKeys.Add(key.Kid, new RsaSecurityKey(rsaProvider));
}
return publicKeys;
}
JWTのアクセストークン検証
private ClaimsPrincipal ValidToken(string token, string issuer, RsaSecurityKey publicKey)
{
//とりあえずこれで、署名・発行者・期限の確認ができる
var validationParams = new TokenValidationParameters
{
ValidIssuer = issuer,
ValidateLifetime = true,
IssuerSigningKey = publicKey,
};
var handler = new JwtSecurityTokenHandler();
var claim = handler.ValidateToken(token, validationParams, out SecurityToken securityToken);
return claim;
}
サンプル
※コストがかかるので、公開鍵の生成までは事前に行うこと
string accessToken = "ey~";
string config = "https://fabrikamb2c.b2clogin.com/fabrikamb2c.onmicrosoft.com/B2C_1_susi_reset_v2//v2.0/.well-known/openid-configuration";
//Endpointを取得する
var openIdConfig = await GetEndPointAsync(config);
//jwks_Uriから公開鍵の生成
var publicKeys = await GetPublicKeyAsync(openIdConfig.jwks_uri);
//JWTのアクセストークン検証
try
{
ValidToken(accessToken, openIdConfig.issuer, publicKeys["xxxxxxxxx"]);
}
catch (SecurityTokenExpiredException)
{
//期限切れ
}
catch(SecurityTokenInvalidSignatureException)
{
//証明書誤り
}
catch (Exception)
{
//その他
}
次回
JWT検証を使いやすいようにアトリビュートで実装したいと思います。
はたしてニーズはあるのか?!