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
,如下所示:
- 获取私钥。
- 每当用户登录时,生成一个 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);
将令牌发送给用户或将其添加到 cookies。
在你的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(添加参考):
TokenValidationParameters
可用于您想要在不访问发行服务器的情况下验证令牌的场景。然后你不能设置Authority
,设置ValidateIssuerSigningKey
和ValidateIssuer
,最后设置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 转发给他们。
这就是我在后端验证 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
,如下所示:
- 获取私钥。
- 每当用户登录时,生成一个 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);
将令牌发送给用户或将其添加到 cookies。
在你的
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(添加参考):
TokenValidationParameters
可用于您想要在不访问发行服务器的情况下验证令牌的场景。然后你不能设置Authority
,设置ValidateIssuerSigningKey
和ValidateIssuer
,最后设置IssuerSigningKey
也就是public 用于验证传入的 JWT 令牌的密钥。
但问题是因为你无法与 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 转发给他们。