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

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

这就是我在后端验证JWT承载令牌的方式:

1
2
3
4
5
6
7
8
9
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服务器通信。这是我得到的错误:

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

我尝试手动输入RSA密钥,但不走运,出现相同错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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);
        }

有什么解决方法吗?


Nan Yu的答案非常准确,您可以使用以下高级选项:

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

  • 请确保您的后端具有作为可信提供者的Auth0的出站连接,以便系统可以以最简单,最标准的方式可靠地运行。

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

我怀疑IT管理员正在尝试实施过时的无互联网政策,这不利于您公司的利益。在IT级别,很容易仅将Auth0 URL列入白名单并阻止其他URL。

下一步,我将尝试说服您的涉众/老板支持标准设置-也许将其转发给他们。


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

但是问题是因为您无法与Auth0对话,这意味着您无法获取最新的公钥来验证Auth0发行的令牌,因此您应确认本地公钥与最新的公钥同步。通过Auth0。如果身份验证也由您控制,则可以考虑使用Identity Server4(它是本地身份验证/ SSO框架),或者可以实现JWT身份验证,如下所示。


因为您是do not have access to the internet,所以您需要具有内部身份和访问控制,例如Identity Server,或创建自己的JWT Issuer/Validator,如下所示:

  • 获取私钥。
  • 每当用户登录时,都会生成一个JWT安全令牌:
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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开始):
  • 1
    var token = new JwtSecurityTokenHandler().WriteToken(jwtToken);
  • 将令牌发送给用户或将其添加到cookie。

  • 在您的startup file中:

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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(添加参考):

    检查本文,以使用JWT保护ASP.NET Core 2.0应用程序。