如何验证来自后端身份提供者的 id 令牌

时间:2021-01-25 12:01:17

标签: asp.net asp.net-web-api jwt openid-connect

我正在开发应用程序,它由 angular 前端和 ASP net Web API 后端(.net 4.5)组成。对于使用 OpenIdConnect 进行身份验证的 iam。我成功地将前端连接到身份提供者,但现在我需要在后端验证 id 令牌,所以我可以肯定,只有经过验证的用户才能调用后端。

此 id 令牌使用 rs256 算法进行签名。所以在后端,我需要做两件事:

  1. 从身份提供者 URL 获取 JWK - 我在这里有点迷茫,我应该通过普通的 HttpClient 获取它,还是有一些库或辅助函数可以做到这一点?

  2. 从 JWK 中生成 RSA 公钥并验证令牌 - 对于使用此函数的此 iam:

         string token="xyz..";
         RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    
         rsa.ImportParameters(
           new RSAParameters()
           {
               Modulus = FromBase64Url("xyz.."),
               Exponent = FromBase64Url("xyz..")
           });
    
         var validationParameters = new TokenValidationParameters
         {
             RequireExpirationTime = true,
             RequireSignedTokens = true,
             ValidateAudience = false,
             ValidateIssuer = false,
             ValidateLifetime = true,
             IssuerSigningKey = new RsaSecurityKey(rsa)
         };
    
         SecurityToken validatedSecurityToken = null;
         var handler = new JwtSecurityTokenHandler();
         handler.ValidateToken(tokenStr, validationParameters, out validatedSecurityToken);
         JwtSecurityToken validatedJwt = validatedSecurityToken as JwtSecurityToken;
    

它可以工作,但现在我需要以某种方式将它与加载的 JWK 连接起来,并注册它以对每个到来的请求使用它。任何建议或简单的例子都会真正帮助我。谢谢。

1 个答案:

答案 0 :(得分:1)

下面的代码取自我的一个培训课程,它会自动下载并验证提供的令牌,我希望您可以将其用作参考。您通常会使用 ConfigurationManager 为您下载 IdentityServer 配置和 JWKS。它还会在内部缓存并定期(每 24 次)重新加载配置。

using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using OpenID_Connect_client.Models;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Threading;

namespace OpenID_Connect_client
{
    public class TokenValidator
    {
        private readonly IOpenIDSettings openIDSettings;

        public TokenValidator(IOpenIDSettings openIDSettings)
        {
            this.openIDSettings = openIDSettings;
        }

        public string ValidateToken(string token, string clientId)
        {
            try
            {
                string issuer = openIDSettings.Issuer;

                var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>($"{issuer}/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever());
                var openIdConfig = configurationManager.GetConfigurationAsync(CancellationToken.None).Result;

                // Configure the TokenValidationParameters. Assign the SigningKeys which were downloaded from Auth0. 
                // Also set the Issuer and Audience(s) to validate
                //https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs
                var validationParameters =
                    new TokenValidationParameters
                    {
                        IssuerSigningKeys = openIdConfig.SigningKeys,

                        ValidAudiences = new[] { clientId },
                        ValidIssuer = issuer,
                        ValidateLifetime = true,
                        ValidateAudience = true,
                        ValidateIssuer = true,
                        ValidateIssuerSigningKey = true,
                        ValidateTokenReplay = true
                    };

                // Now validate the token. If the token is not valid for any reason, an exception will be thrown by the method
                SecurityToken validatedToken;
                JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
                var user = handler.ValidateToken(token, validationParameters, out validatedToken);

                // The ValidateToken method above will return a ClaimsPrincipal. Get the user ID from the NameIdentifier claim
                // (The sub claim from the JWT will be translated to the NameIdentifier claim)
                return $"Token is validated. User Id {user.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value}";
            }
            catch (Exception exc)
            {
                return "Invalid token: " + exc.Message;
            }
        }


    }
}