首页 > 解决方案 > 如何在 webapi 中验证 azure 活动目录令牌

问题描述

我正在尝试验证 angularapp 中的天蓝色活动目录令牌

我在 web api 中使用了以下代码

        [HttpGet]
    [Route("Validate")]
    public JwtSecurityToken Validate(string token)
    {
        string stsDiscoveryEndpoint = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration";


        ConfigurationManager<OpenIdConnectConfiguration> configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint, new OpenIdConnectConfigurationRetriever());

        OpenIdConnectConfiguration config = configManager.GetConfigurationAsync().Result;

        TokenValidationParameters validationParameters = new TokenValidationParameters
        {
            ValidateAudience = false,
            ValidateIssuer = false,
            IssuerSigningTokens = config.SigningTokens,
            ValidateLifetime = false
        };

        JwtSecurityTokenHandler tokendHandler = new JwtSecurityTokenHandler();

        SecurityToken jwt;

        var result = tokendHandler.ValidateToken(token, validationParameters, out jwt);

        return jwt as JwtSecurityToken;
    }

代码在 处显示错误IssuerSigningTokens = config.SigningTokens,并显示消息

TokenValidationParameters 不包含 IssuerSigningTokens 的定义

任何人都可以为我提供解决方案吗?

我也想从 validate 方法返回我自己的令牌。

标签: asp.net-web-apiazure-active-directory

解决方案


今天,我们可以使用jwtSecurityTokenHandlerwith System.IdentityModel.Tokens.Jwt

注意 System.IdentityModel.Tokens.Jwt 版本 5.xx 需要 .NET Framework 5.x。如果目标框架是 .NET Framework 4.5.x 或 4.6.x,则采用 System.IdentityModel.Tokens.Jwt 包的最新稳定 4.xx 版本。

验证智威汤逊

public override async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
    ...

    // validate JWT
    try
    {
        await JwtValidator.ValidateJwtToken(token, cancellationToken);
    }
    catch (SecurityTokenException e)
    {
        var validationSucceeded = false;
        Contract.Assert(validationSucceeded, $"{ErrorCode.UNAUTHORIZED}JWT validation failed ({e.Message}).");
    }

    ...
}

public class JwtValidator
{
    private const string STS_DISCOVERY_ENDPOINT_SUFFIX = ".well-known/openid-configuration";
    private const string URI_DELIMITER = "/";

    public static async Task<SecurityToken> ValidateJwtToken(string token, CancellationToken cancellationToken)
    {
        var aadInstance = "https://login.microsoftonline.com/{0}";
        var tenant = "example.com";
        var audience = "853fb202-4201-4e20-97ae-4d5840d9490f";
        var authority = string.Format(CultureInfo.InvariantCulture, aadInstance, tenant);

        // Fetch configuration
        var stsDiscoveryEndpoint = string.Concat(authority, URI_DELIMITER, STS_DISCOVERY_ENDPOINT_SUFFIX);
        ConfigurationManager<OpenIdConnectConfiguration> configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint);
        var config = await configManager.GetConfigurationAsync(cancellationToken);

        // extract issuer and token for validation
        var issuer = config.Issuer;
        var signingTokens = config.SigningTokens.ToList();

        // validate token
        var validationParameters = CreateTokenValidationParameters(signingTokens, issuer, audience);

        var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();

        SecurityToken jwt;
        jwtSecurityTokenHandler.ValidateToken(token, validationParameters, out jwt);
        return jwt;
    }

    private static TokenValidationParameters CreateTokenValidationParameters(List<SecurityToken> signingTokens, string issuer, string audience)
    {
        Contract.Requires(null != signingTokens);
        Contract.Requires(!string.IsNullOrWhiteSpace(issuer));

        return new TokenValidationParameters()
        {
            ValidAudience = audience,
            ValidIssuer = issuer,
            IssuerSigningTokens = signingTokens,
            CertificateValidator = X509CertificateValidator.None,
            ValidateLifetime = true
        };
    }
}

我也想从 validate 方法返回我自己的令牌。

OpenIdConnectConfiguration configManager.GetConfigurationAsync(cancellationToken);必须在异步上下文中调用 using 时,使用 await(暗示周围的方法必须是异步的)。

否则,方法调用GetConfigurationAsync(cancellationToken)永远不会返回。即使我尝试通过调用 .Result 或使用其他机制同步运行异步方法来同步运行异步方法,该方法也没有返回。

您可以在此博客中查看有关针对 Azure Active Directory 进行手动 JWT 验证的更多详细信息。


推荐阅读