ASP.NET Core:如何在不访问 Internet 的情况下验证 JWT

Posted

技术标签:

【中文标题】ASP.NET Core:如何在不访问 Internet 的情况下验证 JWT【英文标题】:ASP.NET Core: How to validate a JWT without access to the internet 【发布时间】:2020-05-18 13:19:58 【问题描述】:

这就是我在后端验证 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://.auth0.com/.well-known/openid-configuration 与 Auth0 服务器通信。

问题是当我将应用程序部署在无法访问 Internet 的 Intranet 中时,我的应用程序无法与 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);
        

有什么解决方法吗?

【问题讨论】:

使用 keycloak 开源 SSO 作为 JWT Token 验证器。简单又安全 【参考方案1】:

TokenValidationParameters 可用于您想要验证令牌而不访问发行服务器的情况。然后你不能设置 Authority ,设置 ValidateIssuerSigningKeyValidateIssuer ,最后设置 IssuerSigningKey 这是用于验证传入 JWT 令牌的公钥。 Here 和 here 是代码示例。

但问题是因为您无法与 Auth0 交谈,这意味着您无法获得最新的公钥来验证 Auth0 颁发的令牌,您应该确认您的本地公钥与最新的公钥同步通过 Auth0 。如果身份验证也由您控制,您可以考虑使用Identity Server4,这是一个本地身份验证/SSO 框架,或者您可以实现 JWT 身份验证,如here 所示。

【讨论】:

【参考方案2】:

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

    获取私钥。 每当用户登录时,都会生成一个 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
     );

    序列化 JWT(从第 2 步开始):
var token = new JwtSecurityTokenHandler().WriteToken(jwtToken);

    将令牌发送给用户或将其添加到 cookie。

    在你的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"))
         ;
);
    通过添加以下内容来保护您的控制器:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

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


更新1(添加参考):

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

【讨论】:

【参考方案3】:

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

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

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

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

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

下一步,我将尝试说服您的利益相关者/老板支持标准设置 - 或许将这篇文章转发给他们。

【讨论】:

以上是关于ASP.NET Core:如何在不访问 Internet 的情况下验证 JWT的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 EF 的情况下连接到 ASP.NET Core Web API 中的数据库?

ASP.NET Core 6 如何在启动期间访问配置

如何从控制器告诉 ASP.NET Core 视图存在?

如何在 ASP.NET (Core 2) Web 应用程序中访问来自 AWS 的认证?

如何使用 Asp.Net Core 实现基于权限的访问控制

如何从 Asp.NET Core 3.1 启动类访问 launchSettings.json 中的 `applicationUrl` 属性?