【发布时间】:2021-11-29 04:18:22
【问题描述】:
我在 Azure 中使用启用了 Azure Active Directory 身份验证的 WebApp,并且正在从此处的 /.auth/me 页面中提取 id_token:
据我了解,当我将其粘贴到 JWT.io 时,它会通过在 https://login.microsoftonline.com/{tenantId}/v2.0/.well-known/openid-configuration
上查找 OpenId 配置来验证签名然后使用 jwks_uri (https://login.microsoftonline.com/{tenantId}/discovery/v2.0/keys) 从此处的 JWT 标头中找到基于 child 的公共签名密钥(x5c 数组):
但是,当我尝试在 C# 中复制此场景时,我无法使用 System.IdentityModel.Tokens.Jwt 库验证签名。
以下是我的一些尝试和结果:
尝试
var idToken = "{id_token}";
var signingKey = "{x5c[0]}";
SecurityToken validatedToken;
ClaimsPrincipal claimsPrincipal;
var handler = new JwtSecurityTokenHandler();
var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("-----BEGIN CERTIFICATE-----\n" + signingKey + "\n-----END CERTIFICATE-----"));
var tokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = symmetricSecurityKey,
ValidateIssuerSigningKey = true,
ValidateLifetime = false,
ValidateAudience = false,
ValidateIssuer = false
};
try
{
claimsPrincipal = handler.ValidateToken(idToken, tokenValidationParameters, out validatedToken);
Console.WriteLine($"{claimsPrincipal.Identity.Name}");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
结果
IDX10501:签名验证失败。无法匹配键:孩子: '系统.字符串'。捕获的异常:'System.Text.StringBuilder'。 令牌:'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'。
尝试
var kid = "l3sQ-50cCH4xBVZLHTGwnSR7680";
var idToken = "{id_token}";
var signingKey = "{x5c[0]}";
SecurityToken validatedToken;
ClaimsPrincipal claimsPrincipal;
var handler = new JwtSecurityTokenHandler();
var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("-----BEGIN CERTIFICATE-----\n" + signingKey + "\n-----END CERTIFICATE-----")) { KeyId = kid, };
var tokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = symmetricSecurityKey,
ValidateIssuerSigningKey = true,
ValidateLifetime = false,
ValidateAudience = false,
ValidateIssuer = false
};
try
{
claimsPrincipal = handler.ValidateToken(idToken, tokenValidationParameters, out validatedToken);
Console.WriteLine($"{claimsPrincipal.Identity.Name}");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
结果
IDX10511:签名验证失败。尝试过的键: 'System.Text.StringBuilder'。孩子:'System.String'。例外 抓到:'System.Text.StringBuilder'。令牌: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'。
我也尝试了没有 "-----BEGIN CERTIFICATE-----\n" 和 "\n-----END CERTIFICATE--- --" 添加到签名密钥并获得相同的结果以及尝试使用 ASCII 编码而不是 UTF8。
==== 更新 ====
我能够使用 Microsoft.IdentityModel.Protocols 和 Microsoft.IdentityModel.Protocols.OpenIdConnect 库来验证令牌,并使用以下代码创建签名密钥:
var issuer = jwtToken.Issuer;
var audiences = jwtToken.Audiences;
var issuerOpenIdUri = $"{issuer}/.well-known/openid-configuration";
string stsDiscoveryEndpoint = issuerOpenIdUri;
var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint, new OpenIdConnectConfigurationRetriever());
OpenIdConnectConfiguration config = configManager.GetConfigurationAsync().Result;
...然后使用 OpenIdConnectConfiguration 将密钥分配给 TokenValidatetionParameters:
var tokenValidationParameters = new TokenValidationParameters()
{
ValidAudiences = audiences,
ValidIssuer = issuer,
IssuerSigningKeys = config.SigningKeys,
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
ValidateAudience = true,
ValidateIssuer = true
};
但是我仍然很好奇为什么我最初的尝试行不通。我想更好地了解幕后发生的事情。
【问题讨论】:
标签: c# authentication azure-active-directory jwt microsoft-identity-platform