c# - JWT 验证 - sts.windows.net vs login.windows.net:为什么发行人不一致?
问题描述
我正在开发一个应用程序,该应用程序分布在多个Function App
运行在.net5
.
我需要对函数之间的 HTTP 调用进行身份验证。为此,我正在使用Azure Active Directory
. 我在我的租户中创建了一个注册应用程序并生成了一个新密钥。每当Function1需要联系Function2时,我都会从 AAD 检索访问令牌,如下所示:
var stringContent = new StringContent($"grant_type=client_credentials&client_id={Uri.EscapeUriString(clientId)}&client_secret={Uri.EscapeUriString(clientSecret)}&scope={Uri.EscapeUriString(scope)}", Encoding.UTF8, "application/x-www-form-urlencoded");
string tokenUrl = "https://login.microsoftonline.com/57cc008d-ba7c-4887-acfd-93089c705640/oauth2/v2.0/token";
HttpResponseMessage result = await _httpClient.PostAsync(tokenUrl, stringContent);
string content = await result.Content.ReadAsStringAsync();
通过这个调用,我得到一个包含以下信息的令牌:
{
"typ": "JWT",
"alg": "RS256",
"x5t": "XXXXXXXXXXXXX_KXEg",
"kid": "XXXXXXXXXXXXX_KXEg"
}.{
"aud": "api://f87cc6ac-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"iss": "https://sts.windows.net/57cc008d-XXXX-XXXX-XXXX-XXXXXXXXXXXX/",
"iat": 1628443017,
"nbf": 1628443017,
"exp": 1628446917,
"aio": "E2ZgYOg4qv7qZsTRKv5v+XXXXXXXXXXX",
"appid": "f87cc6ac-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"appidacr": "1",
"idp": "https://sts.windows.net/57cc008d-XXXX-XXXX-XXXX-XXXXXXXXXXXX/",
"oid": "39b2e6b8-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"rh": "0.AVsAjQDMV3y6h0is_ZMInHBWQKzGfPhOtBZEj3l003jzIFFbAAA.",
"sub": "39b2e6b8-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"tid": "57cc008d-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"uti": "U7pMFAzw_XXXXXXXXXXXXX",
"ver": "1.0"
}.[Signature]
现在,访问令牌在调用Function2时用作承载令牌。Function2从标头中获取令牌Authorization
并尝试对其进行验证,如下所示:
ConfigurationManager<OpenIdConnectConfiguration> configurationManager = new ("https://login.microsoftonline.com/57cc008d-ba7c-4887-acfd-93089c705640/v2.0/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever());
OpenIdConnectConfiguration openIdConnectConfiguration = await configurationManager.GetConfigurationAsync();
TokenValidationParameters validationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = true,
ValidIssuers = new[]
{
openIdConnectConfiguration.Issuer
},
ValidateIssuerSigningKey = true,
IssuerSigningKeys = openIdConnectConfiguration.SigningKeys,
RequireExpirationTime = true,
ValidateLifetime = true,
RequireSignedTokens = true,
};
JwtSecurityTokenHandler securityTokenHandler = new();
if (!securityTokenHandler.CanReadToken(cleanedBearerToken))
throw new ArgumentException("Unable to read the token. It is malformed.");
try
{
ClaimsPrincipal claimsPrincipal = securityTokenHandler.ValidateToken(cleanedBearerToken, validationParameters, out SecurityToken _);
return claimsPrincipal;
}
catch (Exception unhandledException)
{
throw new AuthenticationException("The token could not be validated.", unhandledException);
}
除了发行人之外,验证也有效。使用此设置,无法验证颁发者。该令牌表明发行人来自sts.windows.net
。但是,OpenID 配置声明颁发者必须是login.microsoft.com
.
为了使它工作,我已经退回到这样的东西,这是不太理想的,因为我必须忽略openid-configuration
端点返回的参数(它必须更好地知道我):
TokenValidationParameters validationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = true,
ValidIssuers = new[]
{
// --> Force the use of the following issuer!!
"https://sts.windows.net/57cc008d-ba7c-4887-acfd-93089c705640/"
},
ValidateIssuerSigningKey = true,
IssuerSigningKeys = openIdConnectConfiguration.SigningKeys,
RequireExpirationTime = true,
ValidateLifetime = true,
RequireSignedTokens = true,
};
问题
发行人的优先权是一种好的做法吗?如果不是,我该怎么做才能从 Azure Active Directory 获得一致的颁发者并避免自己指定颁发者?
解决方案
颁发者值取决于访问令牌版本。如果您查看 jwt.ms 中的示例令牌,您将看到访问令牌 V1 的颁发者是https://sts.windows.net/...
,访问令牌 V2 的颁发者是https://login.microsoft.com/...
此外,如果您检查 OIDC 元数据端点 v1 ( https://login.microsoftonline.com/common/.well-known/openid-configuration ),则颁发者将是sts.windows.net
OIDC 元数据端点 v2 ( https://login.microsoftonline。 com/common/v2.0/.well-known/openid-configuration),发行者将是login.microsoft.com
.
更新
在已注册应用程序的清单中,查找 的值accessTokenAcceptedVersion
:
将其更改为 2 并且发行人将变为login.microsoft.com
而不是sts.windows.net
.