【问题标题】:How to validate id token from identity provider on backend如何在后端验证身份提供者的 id 令牌
【发布时间】:2021-04-29 05:36:38
【问题描述】:

我正在开发应用程序,该应用程序由 Angular 前端和 ASP 网络 Web API 后端(.net 4.5)组成。使用 OpenIdConnect 进行身份验证。我成功地将前端连接到身份提供者,但现在我需要在后端验证 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 连接起来,并注册它以将其用于每个到来的请求。任何建议或简单的例子都会对我有帮助。谢谢。

【问题讨论】:

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


    【解决方案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;
                }
            }
    
    
        }
    }
    

    【讨论】:

    • 非常感谢,加载身份提供者配置就像一个魅力。我不知道的最后一件事是如何连接它,所以到达我后端的每个请求都首先使用这个函数进行验证。我可以在 Startup.cs 中使用 app.UseJwtBearerAuthentication 之类的东西,还是我必须做出不同的做法?
    • 如果您添加 UseJwtBearerAuthentication,它将为您处理令牌下载和验证。这是否使这是一个可以接受的答案?
    • 另外,一个好的建议是永远不要将客户端或 API 与 IdentityServer 放在同一个服务中,最好将它们全部分开,因为当它们不在同一个盒子。
    猜你喜欢
    • 1970-01-01
    • 2017-06-19
    • 2020-06-03
    • 2013-05-05
    • 1970-01-01
    • 2021-11-03
    • 2016-01-05
    • 2016-05-08
    • 1970-01-01
    相关资源
    最近更新 更多