Azure AD - 为什么我不能验证由Azure AD为我的Web API发布的JWT令牌?出现“IDX10516:签名验证失败”错误。

4

我有一个被Azure AD保护的Web API。我能够从Azure AD获取Web API的访问令牌,并成功使用它。

我想要做的是在使用该令牌执行任何操作之前验证该令牌,以便在令牌存在问题时向用户提供有意义的错误信息。例如,我想告诉用户的一些事情是:

  1. 令牌是否已过期?
  2. 令牌是否为正确的受众获得?
  3. 令牌发行者是否有效?

但是,我无法这样做,因为无论令牌是否有效,我都会不断收到以下错误消息:

IDX10516: Signature validation failed. Unable to match key: 
kid: 'System.String'.
Exceptions caught:
 'System.Text.StringBuilder'. 
token: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'. Valid Lifetime: 'System.Boolean'. Valid Issuer: 'System.Boolean'

我成功地解析了位于https://jwt.io的令牌。

在那里的“Header”部分中,我看到了以下内容:

{
  "typ": "JWT",
  "alg": "RS256",
  "x5t": "qDm8HXaLQBeSIvYXzMt8PQ_ADFt",//obfuscated
  "kid": "qDm8HXaLQBeSIvYXzMt8PQ_ADFt"//obfuscated
}

另外,我也收到了如下截图所示的签名已验证消息。

enter image description here

这是我编写的代码:

string authorizationToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Im5PbzNaRHJPRFhFSzFqS1doWHNsSFJfS1hFZyIsImt...";
try
{
    JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();

    TokenValidationParameters tokenValidationParameters = new TokenValidationParameters()
    {
        ValidateLifetime = true,
    };
    var claimsPrincipal = tokenHandler.ValidateToken(authorizationToken, tokenValidationParameters, out _);//Exception comes on this line.
}
catch (SecurityTokenExpiredException exception)
{
    //Do something with the token expired exception
}
catch (SecurityTokenInvalidAudienceException exception)
{
    //Do something with invalid audience exception
}
catch (Exception exception) //Code always lands in this exception block
{
    //Token is invalid because of some other reason
}

正如我上面所说的,无论令牌是否有效,我的代码始终落在最后一个异常块中。
请问有人能告诉我我在这里做错了什么?需要什么才能成功验证令牌?
非常感谢任何对此的见解。
1个回答

5

要验证令牌,您需要指定身份提供者(Azure AD)用于签署该令牌的密钥:

using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var token = "<my token>";
            var tenantid = "<my azure ad  tenant id>";

            // => use to retrieve the keys used by AAD to sign the token
            var openidConfigManaged = new ConfigurationManager<OpenIdConnectConfiguration>(
                $"https://login.microsoftonline.com/{tenantid}/v2.0/.well-known/openid-configuration",
                new OpenIdConnectConfigurationRetriever(),
                new HttpDocumentRetriever());
            var config = await openidConfigManaged.GetConfigurationAsync();

            var parameteres = new TokenValidationParameters()
            {
                RequireAudience = true,
                RequireExpirationTime = true,
                ValidateAudience = true,
                ValidateIssuer = true,
                ValidateLifetime = true,
                // The Audience should be the requested resource => client_id and or resource identifier.
                // Refer to the "aud" claim in the token
                ValidAudiences = new[] { "<my client id or resource identitifer>" },
                // The issuer is the identity provider
                // Refer to the "iss" claim in the token
                ValidIssuers = new[] { $"https://sts.windows.net/{tenantid}/" }, 
                IssuerSigningKeys = config.SigningKeys
            };

            var tokenHandler = new JwtSecurityTokenHandler();
            var claimPrincipal = tokenHandler.ValidateToken(token, parameteres, out _);
        }
    }
}

1
没问题,是的,你的假设是正确的。 关于 open-id 配置端点,您可以参考这篇文章:https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc#fetch-the-openid-connect-metadata-document - Thomas
1
对于发行者,您也可以查看此文档:https://learn.microsoft.com/zh-cn/azure/active-directory/develop/access-tokens#payload-claims - Thomas
1
谢谢Thomas!非常感谢你在这方面的帮助。我还有一些其他的疑问,但我会在另一个问题中提出它们。 - Gaurav Mantri
1
Net Core还提供了最简单的配置Azure AD身份验证的方式:https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-v2-aspnet-core-webapp - Thomas
1
谢谢您提供这些链接,非常感谢。让我仔细研究一下。我这个"天真"的人认为我必须自己实现所有东西,希望能证明自己是错的:D。 - Gaurav Mantri
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接