ASP.NET 核心:如何在不访问互联网的情况下验证 JWT

ASP.NET Core: How to validate a JWT without access to the internet

这就是我在后端验证 JWT 不记名令牌的方式:

services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                options.Authority = $"https://{Configuration["Auth0:Authority"]}";
                options.Audience = Configuration["Auth0:Audience"];
            });

它工作正常,因为 .Net 核心咨询权威机构以在后台获取所需信息(例如签名密钥)。在我的例子中,它通过 https://< MY TENANT > .auth0.com/.well-known/openid-configuration.

与 Auth0 服务器通信

问题是当我将应用程序部署到无法访问互联网的内联网时,我的应用程序无法与 Auth0 服务器通信。这是我得到的错误:

System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://< My TENANT >.auth0.com/.well-known/openid-configuration'.

我尝试手动输入 RSA 密钥,但运气不好,出现同样的错误:

AddJwtBearer(options =>
            {
                options.Authority = $"https://{Configuration["Auth0:Domain"]}";
                options.Audience = Configuration["Auth0:Audience"];
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateLifetime = true,
                    RequireSignedTokens = true,
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = GetRsaKey(),
                };
            }); 

 private SecurityKey GetRsaKey()
        {
            byte[] modulus = Decode("r5cpJ....-fUGjJCH1QQ");
            byte[] exponent = Decode("A...AB");

            var rsaParameters = new RSAParameters
            {
                Modulus = modulus,
                Exponent = exponent
            };

            using var rsaProvider = new RSACryptoServiceProvider();
            rsaProvider.ImportParameters(rsaParameters);
            return new RsaSecurityKey(rsaProvider);
        }

任何解决方法?

由于您 do not have access to the internet 您需要像 Identity Server 一样拥有本地身份和访问控制,或者创建您自己的 JWT Issuer/Validator,如下所示:

  1. 获取私钥。
  2. 每当用户登录时,生成一个 JWT 安全令牌:
private JwtSecurityToken GetJwtSecurityToken(List<Claim> user_claims)
{
     string privateKey = "YOUR_PRIVATE_KEY";
     var symmetricKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(privateKey));
     var credentials = new SigningCredentials(symmetricKey, SecurityAlgorithms.HmacSha256);

     return new JwtSecurityToken
     (
          issuer: "ISSUER_NAME",
          audience: "AUDIENCE",
          claims: user_claims,
          signingCredentials: credentials
     );
}
  1. 序列化 JWT(来自第 2 步):
var token = new JwtSecurityTokenHandler().WriteToken(jwtToken);
  1. 将令牌发送给用户或将其添加到 cookies。

  2. 在你的startup file:

services.AddAuthentication()
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, config =>
    {
        config.TokenValidationParameters = new TokenValidationParameters()
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = "ISSUER",
            ValidAudience = "AUDIENCE",
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YOUR_PRIVATE_KEY"))
         };
});
  1. 通过添加以下内容来保护您的控制器:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

就是这样。希望有人会告诉我们是否有更好的解决方案。


更新 1(添加参考):

查看这篇文章Securing ASP.NET Core 2.0 Applications with JWTs

TokenValidationParameters 可用于您想要在不访问发行服务器的情况下验证令牌的场景。然后你不能设置Authority,设置ValidateIssuerSigningKeyValidateIssuer,最后设置IssuerSigningKey也就是public 用于验证传入的 JWT 令牌的密钥。 and here 是代码示例。

但问题是因为你无法与 Auth0 对话,这意味着你无法获得最新的 publick 密钥来验证 Auth0 颁发的令牌,你应该确认你的本地 public 密钥与 Auth0 最新的 publich 同步。如果身份验证也由您控制,您可以考虑使用 Identity Server4 which is a local authentication/SSO framework , or you can implement JWT authentication as shown here .

南宇的回答非常准确,你有这些高级选项:

  • 配置固定密钥并在后端用它验证令牌。这会工作一段时间,但如果密钥未可靠同步并且 Auth0 更新令牌签名密钥,将来可能会严重崩溃,可能会给您的公司带来严重问题。

  • 确保您的后端作为受信任的提供者与 Auth0 有出站连接,以便系统能够以最简单和最标准的方式可靠地工作。

这感觉像是人和流程问题,而不是技术问题。我不会尝试通过更改代码来解决它。

我怀疑 IT 管理员正试图执行不符合贵公司利益的过时的禁止互联网政策。在 IT 级别,很容易仅将 Auth0 URL 列入白名单并阻止其他 URL。

作为下一步,我将尝试说服您的利益相关者/老板支持标准设置 - 也许将此 post 转发给他们。