首页 > 解决方案 > 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 获得一致的颁发者并避免自己指定颁发者?

标签: c#azure-active-directoryjwtazure-functions

解决方案


颁发者值取决于访问令牌版本。如果您查看 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.netOIDC 元数据端点 v2 ( https://login.microsoftonline。 com/common/v2.0/.well-known/openid-configuration),发行者将是login.microsoft.com.

更新

在已注册应用程序的清单中,查找 的值accessTokenAcceptedVersion

在此处输入图像描述

将其更改为 2 并且发行人将变为login.microsoft.com而不是sts.windows.net.

在此处输入图像描述


推荐阅读