现有 .NET Framework 应用程序可创建 Bearer 令牌。另一个现有的 .NET Framework 代码应用程序能够识别令牌以进行身份验证和授权。使用 RSA 安全密钥,因此它不像我之前在该主题上的工作那么简单。
我的任务是创建一个也能够识别相同令牌的 .NET 7 应用程序。我没有成功。这就是我在一个 .NET 7 应用程序中隔离该问题的原因。希望有人可以修复我的扩展方法,使其能够正常工作。
让我向您展示我的扩展方法:
public static IServiceCollection AddCustomJwtAuthentication(this IServiceCollection services, AuthConfiguration authConfiguration)
{
// Initialize RSA parameters for public key
var rsa = new RSACryptoServiceProvider(2048);
rsa.FromXmlString(authConfiguration.OAuthAccessTokenSigningKeyPublic);
var rsaPublicKey = new RsaSecurityKey(rsa.ExportParameters(false));
var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authConfiguration.OAuthTokenEncryptionKey));
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
AuthenticationType = "Bearer",
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = authConfiguration.OAuthIssuer,
ValidAudience = authConfiguration.OAuthAudience,
IssuerSigningKey = rsaPublicKey, // Used for verifying the token's signature
TokenDecryptionKey = symmetricSecurityKey, // Used for decrypting the token's payload
ValidAlgorithms = new[]
{
SecurityAlgorithms.RsaSha512Signature, // For signature verification
SecurityAlgorithms.Aes256KW, // For key wrapping during decryption
SecurityAlgorithms.Aes128CbcHmacSha256 // For content encryption/decryption
}
};
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
Console.WriteLine($"OnAuthenticationFailed {context.Exception}");
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Append("Token-Expired", $"{true}");
}
return Task.CompletedTask;
},
OnTokenValidated = context =>
{
Console.WriteLine($"OnTokenValidated: with SecurityToken valid to {context.SecurityToken.ValidTo}");
return Task.CompletedTask;
},
OnChallenge = context =>
{
Console.WriteLine($"OnChallenge: {context.Error} - {context.ErrorDescription}");
return Task.CompletedTask;
}
};
});
return services;
}
我也会展示我的代币创建者:
public class TokenCreator
{
private const int KeySize = 2048;
private readonly string _issuer;
private readonly string _audience;
private readonly SymmetricSecurityKey _encryptionKey;
private readonly EncryptingCredentials _encryptingCredentials;
private SigningCredentials _signingCredentials;
private TokenCreator(string encryptionKey, string issuer, string audience)
{
if (string.IsNullOrWhiteSpace(encryptionKey)) throw new ArgumentNullException(nameof(encryptionKey));
_issuer = issuer;
_audience = audience;
_encryptionKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(encryptionKey));
_encryptingCredentials = new EncryptingCredentials(
_encryptionKey,
SecurityAlgorithms.Aes256KW,
SecurityAlgorithms.Aes128CbcHmacSha256);
}
public TokenCreator(AuthConfiguration authConfiguration) : this (authConfiguration.OAuthTokenEncryptionKey,
authConfiguration.OAuthIssuer, authConfiguration.OAuthAudience)
{
SetSigningCredentials(authConfiguration.OAuthAccessTokenSigningKeyPrivate);
}
private void SetSigningCredentials(string privateSigningKeyXml)
{
if (string.IsNullOrWhiteSpace(privateSigningKeyXml)) throw new ArgumentNullException(nameof(privateSigningKeyXml));
using (var rsa = new RSACryptoServiceProvider(KeySize))
{
rsa.FromXmlString(privateSigningKeyXml);
_signingCredentials = new SigningCredentials(new RsaSecurityKey(rsa.ExportParameters(true)), SecurityAlgorithms.RsaSha512Signature);
}
}
public virtual string CreateToken(DateTime expires, DateTime issued)
{
// Define claims
var claims = new List<Claim>
{
new(ClaimTypes.Name, "John Doe"),
new(ClaimTypes.Email, "[email protected]"),
new(ClaimTypes.Role, "Administrator"),
new("CustomClaimType", "CustomClaimValue")
};
var identity = new ClaimsIdentity(claims, "Bearer");
var handler = new JwtSecurityTokenHandler();
var token = handler.CreateJwtSecurityToken(_issuer, _audience, identity, null, expires, issued, _signingCredentials, _encryptingCredentials);
var jwt = handler.WriteToken(token);
return jwt;
}
}
我也会分享我的节目课:
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var authConfiguration = builder.Configuration.GetSection(nameof(AuthConfiguration)).Get<AuthConfiguration>()!;
builder.Services.AddCustomJwtAuthentication(authConfiguration);
var tokenCreator = new TokenCreator(authConfiguration);
var token = tokenCreator.CreateToken(DateTime.UtcNow.AddHours(1), DateTime.UtcNow);
Console.WriteLine("Token is coming");
Console.WriteLine(token);
Console.WriteLine("End of token");
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
由于这个 Web api 为我生成了一个令牌,我可以直接使用 VSCode REST Client 进行测试:
GET https://localhost:7134/api/Authentication/verifyAuthentication
Authorization: Bearer SUPERLONGTOKEN
这是调用我的控制器方法:
[Route("api/[controller]")]
[ApiController]
public class AuthenticationController : ControllerBase
{
[HttpGet("verifyAuthentication")]
[Authorize]
public IActionResult VerifyAuthentication()
{
return Ok("Auth succeeded");
}
}
这给出了以下输出:
HTTP/1.1 401 Unauthorized
Content-Length: 0
Connection: close
Date: Tue, 11 Jun 2024 12:26:12 GMT
Server: Kestrel
WWW-Authenticate: Bearer error="invalid_token", error_description="The signature key was not found"
代币生成成功,所以这不是我关心的问题。为了能够使用它,我需要使用与 .NET Framework 代码相同的键来编写扩展方法。显然,我没有正确执行此操作,因为我没有收到 200 的退款。那么,当需要 RsaSecurityKey 时,需要更改哪些内容来处理 .NET 7 中的 Bearer 令牌?
要使用 RSA 安全密钥处理 .NET 7 中的承载令牌,您需要配置 JWT 承载身份验证以使用 RSA 密钥进行令牌验证。这是分步指南:
安装所需的软件包: 确保您已安装 JWT Bearer 包:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
在
Program.cs
中配置JWT身份验证:
更新您的 Program.cs
以添加具有 RSA 安全密钥配置的 JWT Bearer 身份验证。这是一个例子:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Security.Cryptography;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Configure JWT authentication
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
// Load RSA public key
var rsa = new RSACryptoServiceProvider();
rsa.ImportRSAPublicKey(
source: Convert.FromBase64String(builder.Configuration["Jwt:PublicKey"]), // your RSA public key
bytesRead: out _
);
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new RsaSecurityKey(rsa)
};
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
应用程序设置配置: 确保您的
appsettings.json
包含必要的 JWT 配置:
{
"Jwt": {
"Issuer": "your_issuer",
"Audience": "your_audience",
"PublicKey": "your_rsa_public_key_base64"
}
}
保护您的控制器操作: 使用
[Authorize]
属性来保护您的 API 端点:
[ApiController]
[Route("[controller]")]
[Authorize]
public class YourController : ControllerBase
{
// Your actions here
}
生成 RSA 密钥: 如果您尚未生成 RSA 密钥,则可以使用 OpenSSL 等工具或在 .NET 中以编程方式生成它们。确保公钥正确编码为 Base64,以便在
appsettings.json
中使用。
遵循这些步骤应该可以帮助您配置 .NET 7 以使用 RSA 安全密钥进行令牌验证来处理 JWT Bearer 令牌。此设置可确保您的令牌根据 RSA 密钥进行验证,从而提供强大且安全的身份验证机制。