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://
问题是当我将应用程序部署在无法访问 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
,设置 ValidateIssuerSigningKey
和 ValidateIssuer
,最后设置 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 2) Web 应用程序中访问来自 AWS 的认证?
如何从 Asp.NET Core 3.1 启动类访问 launchSettings.json 中的 `applicationUrl` 属性?