24 changed files with 1200 additions and 165 deletions
@ -0,0 +1,211 @@ |
|||
# JWT 实现指南 |
|||
|
|||
## 1. JwtOptions(配置类) |
|||
|
|||
### 1.1 主要职责 |
|||
- 存储和管理 JWT 相关的所有配置项 |
|||
- 提供配置验证功能 |
|||
- 支持从配置文件加载配置 |
|||
|
|||
### 1.2 关键配置项 |
|||
```csharp |
|||
public class JwtOptions |
|||
{ |
|||
public string SecretKey { get; set; } // JWT 密钥 |
|||
public string Issuer { get; set; } // 颁发者 |
|||
public string Audience { get; set; } // 受众 |
|||
public int ExpiryMinutes { get; set; } // 访问令牌过期时间 |
|||
public int RefreshTokenExpiryDays { get; set; } // 刷新令牌过期时间 |
|||
public int ClockSkewMinutes { get; set; } // 时钟偏差 |
|||
public int KeyRotationDays { get; set; } // 密钥轮换间隔 |
|||
public int MinKeyLength { get; set; } // 密钥最小长度 |
|||
} |
|||
``` |
|||
|
|||
### 1.3 配置验证 |
|||
- 验证所有必需字段不为空 |
|||
- 验证数值字段的有效性 |
|||
- 验证密钥格式和长度 |
|||
|
|||
## 2. JwtOptionsExtensions(扩展方法类) |
|||
|
|||
### 2.1 主要职责 |
|||
- 提供 JwtOptions 的扩展功能 |
|||
- 实现密钥强度验证 |
|||
- 提供熵值计算功能 |
|||
|
|||
### 2.2 关键方法 |
|||
```csharp |
|||
public static class JwtOptionsExtensions |
|||
{ |
|||
// 验证密钥强度 |
|||
public static void ValidateKeyStrength(this JwtOptions options) |
|||
|
|||
// 计算字符串熵值 |
|||
private static double CalculateEntropy(string input) |
|||
} |
|||
``` |
|||
|
|||
### 2.3 验证标准 |
|||
- 密钥不能为空 |
|||
- 密钥必须是有效的 Base64 字符串 |
|||
- 密钥长度必须满足最小长度要求 |
|||
- 密钥熵值必须大于 3.5(确保足够的随机性) |
|||
|
|||
## 3. KeyRotationService(密钥管理服务) |
|||
|
|||
### 3.1 主要职责 |
|||
- 管理 JWT 密钥的生命周期 |
|||
- 实现密钥自动轮换 |
|||
- 提供密钥生成和验证功能 |
|||
|
|||
### 3.2 关键功能 |
|||
- 密钥初始化 |
|||
- 密钥轮换 |
|||
- 密钥强度验证 |
|||
- 密钥缓存管理 |
|||
|
|||
### 3.3 安全特性 |
|||
- 定期自动轮换密钥 |
|||
- 支持密钥预热 |
|||
- 防止密钥泄露 |
|||
- 密钥强度保证 |
|||
|
|||
## 4. JwtProvider(JWT 令牌提供者) |
|||
|
|||
### 4.1 主要职责 |
|||
- 生成 JWT 访问令牌和刷新令牌 |
|||
- 验证 JWT 令牌 |
|||
- 管理令牌黑名单 |
|||
- 提供令牌解析功能 |
|||
|
|||
### 4.2 关键方法 |
|||
```csharp |
|||
public interface IJwtProvider |
|||
{ |
|||
string GenerateAccessToken(IEnumerable<Claim> claims); |
|||
string GenerateRefreshToken(IEnumerable<Claim> claims); |
|||
bool ValidateToken(string token); |
|||
void RevokeToken(string token); |
|||
void AddToBlacklist(string token); |
|||
IEnumerable<Claim> GetClaimsFromToken(string token); |
|||
} |
|||
``` |
|||
|
|||
### 4.3 安全特性 |
|||
- 令牌撤销机制 |
|||
- 令牌黑名单 |
|||
- 完整的令牌验证 |
|||
- 支持自定义声明 |
|||
|
|||
## 5. JwtBearerOptionsSetup(JWT Bearer 认证配置) |
|||
|
|||
### 5.1 主要职责 |
|||
- 配置 ASP.NET Core JWT Bearer 认证 |
|||
- 设置令牌验证参数 |
|||
- 配置认证事件处理 |
|||
|
|||
### 5.2 关键配置 |
|||
```csharp |
|||
public class JwtBearerOptionsSetup : IConfigureOptions<JwtBearerOptions> |
|||
{ |
|||
public void Configure(JwtBearerOptions options) |
|||
{ |
|||
// 配置令牌验证参数 |
|||
options.TokenValidationParameters = new TokenValidationParameters |
|||
{ |
|||
ValidateIssuer = true, |
|||
ValidIssuer = _jwtOptions.Issuer, |
|||
ValidateAudience = true, |
|||
ValidAudience = _jwtOptions.Audience, |
|||
ValidateLifetime = true, |
|||
// ... 其他配置 |
|||
}; |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### 5.3 安全特性 |
|||
- 强制使用 HTTPS |
|||
- 完整的令牌验证 |
|||
- 详细的日志记录 |
|||
- 异常处理机制 |
|||
|
|||
## 安全最佳实践 |
|||
|
|||
1. **密钥管理** |
|||
- 使用足够长的随机密钥 |
|||
- 定期轮换密钥 |
|||
- 使用安全的密钥存储机制 |
|||
|
|||
2. **令牌安全** |
|||
- 设置合理的过期时间 |
|||
- 实现令牌撤销机制 |
|||
- 使用令牌黑名单 |
|||
|
|||
3. **传输安全** |
|||
- 强制使用 HTTPS |
|||
- 验证令牌签名 |
|||
- 验证令牌来源 |
|||
|
|||
4. **配置安全** |
|||
- 验证所有配置项 |
|||
- 使用强类型配置 |
|||
- 避免硬编码敏感信息 |
|||
|
|||
## 使用示例 |
|||
|
|||
### 1. 配置 JWT 选项 |
|||
```csharp |
|||
services.Configure<JwtOptions>(configuration.GetSection(JwtOptions.SectionName)); |
|||
``` |
|||
|
|||
### 2. 注册服务 |
|||
```csharp |
|||
services.AddScoped<IJwtProvider, JwtProvider>(); |
|||
services.AddScoped<IKeyRotationService, KeyRotationService>(); |
|||
services.AddSingleton<IConfigureOptions<JwtBearerOptions>, JwtBearerOptionsSetup>(); |
|||
``` |
|||
|
|||
### 3. 使用 JWT 提供者 |
|||
```csharp |
|||
public class AuthController : ControllerBase |
|||
{ |
|||
private readonly IJwtProvider _jwtProvider; |
|||
|
|||
public AuthController(IJwtProvider jwtProvider) |
|||
{ |
|||
_jwtProvider = jwtProvider; |
|||
} |
|||
|
|||
public IActionResult Login(LoginRequest request) |
|||
{ |
|||
// 验证用户 |
|||
var claims = GetUserClaims(user); |
|||
var token = _jwtProvider.GenerateAccessToken(claims); |
|||
return Ok(new { token }); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## 注意事项 |
|||
|
|||
1. **密钥管理** |
|||
- 不要在代码中硬编码密钥 |
|||
- 使用环境变量或密钥管理服务 |
|||
- 定期轮换密钥 |
|||
|
|||
2. **令牌配置** |
|||
- 设置合理的过期时间 |
|||
- 启用所有安全验证 |
|||
- 使用 HTTPS |
|||
|
|||
3. **错误处理** |
|||
- 实现完整的错误处理 |
|||
- 记录详细的日志 |
|||
- 返回适当的错误信息 |
|||
|
|||
4. **性能考虑** |
|||
- 使用缓存机制 |
|||
- 优化令牌验证 |
|||
- 控制令牌大小 |
@ -0,0 +1,217 @@ |
|||
# JWT 服务注册指南 |
|||
|
|||
## 服务注册概览 |
|||
|
|||
JWT 相关的服务注册主要分布在两个位置: |
|||
1. `Program.cs` - Web API 层的服务注册 |
|||
2. `DependencyInjection.cs` - 基础设施层的服务注册 |
|||
|
|||
## 1. 基础设施层注册 (DependencyInjection.cs) |
|||
|
|||
### 1.1 JWT 配置注册 |
|||
```csharp |
|||
// 配置 JWT 选项 |
|||
services.Configure<JwtOptions>(configuration.GetSection(JwtOptions.SectionName)); |
|||
services.AddSingleton<IConfigureOptions<JwtBearerOptions>, JwtBearerOptionsSetup>(); |
|||
services.AddScoped<IJwtProvider, JwtProvider>(); |
|||
``` |
|||
|
|||
说明: |
|||
- `Configure<JwtOptions>`: 从配置文件加载 JWT 配置 |
|||
- `JwtBearerOptionsSetup`: 配置 JWT Bearer 认证选项 |
|||
- `JwtProvider`: 实现 JWT 令牌的生成和验证 |
|||
|
|||
### 1.2 密钥管理服务注册 |
|||
```csharp |
|||
// 注册密钥轮换服务 |
|||
services.AddSingleton<IKeyRotationService, KeyRotationService>(); |
|||
services.AddHostedService<KeyRotationBackgroundService>(); |
|||
``` |
|||
|
|||
说明: |
|||
- `KeyRotationService`: 管理 JWT 密钥的生命周期 |
|||
- `KeyRotationBackgroundService`: 后台服务,定期执行密钥轮换 |
|||
|
|||
### 1.3 认证服务注册 |
|||
```csharp |
|||
// 配置JWT认证 |
|||
services.AddAuthentication(options => |
|||
{ |
|||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; |
|||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; |
|||
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; |
|||
}) |
|||
.AddJwtBearer(); |
|||
|
|||
services.AddAuthorization(); |
|||
``` |
|||
|
|||
说明: |
|||
- 设置默认认证方案为 JWT Bearer |
|||
- 启用授权服务 |
|||
|
|||
## 2. Web API 层注册 (Program.cs) |
|||
|
|||
### 2.1 JWT 配置注册 |
|||
```csharp |
|||
// 配置JWT认证 |
|||
builder.Services.Configure<JwtOptions>(builder.Configuration.GetSection("JwtOptions")); |
|||
builder.Services.AddSingleton<IConfigureOptions<JwtBearerOptions>, JwtBearerOptionsSetup>(); |
|||
``` |
|||
|
|||
### 2.2 认证服务注册 |
|||
```csharp |
|||
builder.Services.AddAuthentication(options => |
|||
{ |
|||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; |
|||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; |
|||
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; |
|||
}) |
|||
.AddJwtBearer(); |
|||
``` |
|||
|
|||
### 2.3 Swagger 配置 |
|||
```csharp |
|||
builder.Services.AddSwaggerGen(options => |
|||
{ |
|||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme |
|||
{ |
|||
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", |
|||
Name = "Authorization", |
|||
In = ParameterLocation.Header, |
|||
Type = SecuritySchemeType.ApiKey, |
|||
Scheme = "Bearer" |
|||
}); |
|||
|
|||
options.AddSecurityRequirement(new OpenApiSecurityRequirement |
|||
{ |
|||
{ |
|||
new OpenApiSecurityScheme |
|||
{ |
|||
Reference = new OpenApiReference |
|||
{ |
|||
Type = ReferenceType.SecurityScheme, |
|||
Id = "Bearer" |
|||
} |
|||
}, |
|||
Array.Empty<string>() |
|||
} |
|||
}); |
|||
}); |
|||
``` |
|||
|
|||
## 3. 服务注册优化建议 |
|||
|
|||
### 3.1 避免重复注册 |
|||
目前存在重复注册的问题: |
|||
1. JWT 配置在两个地方都进行了注册 |
|||
2. 认证服务在两个地方都进行了配置 |
|||
|
|||
建议优化方案: |
|||
```csharp |
|||
// 在 DependencyInjection.cs 中统一注册 |
|||
public static IServiceCollection AddJwtServices( |
|||
this IServiceCollection services, |
|||
IConfiguration configuration) |
|||
{ |
|||
// 配置 JWT 选项 |
|||
services.Configure<JwtOptions>(configuration.GetSection(JwtOptions.SectionName)); |
|||
|
|||
// 注册 JWT 服务 |
|||
services.AddSingleton<IConfigureOptions<JwtBearerOptions>, JwtBearerOptionsSetup>(); |
|||
services.AddScoped<IJwtProvider, JwtProvider>(); |
|||
services.AddSingleton<IKeyRotationService, KeyRotationService>(); |
|||
services.AddHostedService<KeyRotationBackgroundService>(); |
|||
|
|||
// 配置认证 |
|||
services.AddAuthentication(options => |
|||
{ |
|||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; |
|||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; |
|||
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; |
|||
}) |
|||
.AddJwtBearer(); |
|||
|
|||
services.AddAuthorization(); |
|||
|
|||
return services; |
|||
} |
|||
``` |
|||
|
|||
### 3.2 配置文件结构 |
|||
建议的 JWT 配置结构: |
|||
```json |
|||
{ |
|||
"JwtOptions": { |
|||
"SecretKey": "your-secret-key", |
|||
"Issuer": "your-issuer", |
|||
"Audience": "your-audience", |
|||
"ExpiryMinutes": 15, |
|||
"RefreshTokenExpiryDays": 7, |
|||
"ClockSkewMinutes": 5, |
|||
"KeyRotationDays": 30, |
|||
"MinKeyLength": 64 |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## 4. 中间件配置 |
|||
|
|||
### 4.1 认证中间件 |
|||
```csharp |
|||
// 启用认证中间件 |
|||
app.UseAuthentication(); |
|||
|
|||
// 启用授权中间件 |
|||
app.UseAuthorization(); |
|||
``` |
|||
|
|||
### 4.2 HTTPS 重定向 |
|||
```csharp |
|||
// 启用 HTTPS 重定向 |
|||
app.UseHttpsRedirection(); |
|||
``` |
|||
|
|||
## 5. 使用建议 |
|||
|
|||
1. **配置管理** |
|||
- 使用强类型配置 |
|||
- 集中管理配置项 |
|||
- 避免硬编码敏感信息 |
|||
|
|||
2. **服务注册** |
|||
- 使用扩展方法组织服务注册 |
|||
- 避免重复注册 |
|||
- 遵循依赖注入最佳实践 |
|||
|
|||
3. **安全配置** |
|||
- 启用 HTTPS |
|||
- 配置适当的 CORS 策略 |
|||
- 实现完整的认证和授权 |
|||
|
|||
4. **开发体验** |
|||
- 配置 Swagger 文档 |
|||
- 提供详细的错误信息 |
|||
- 实现适当的日志记录 |
|||
|
|||
## 6. 常见问题 |
|||
|
|||
1. **配置加载失败** |
|||
- 检查配置文件路径 |
|||
- 验证配置节点名称 |
|||
- 确保配置值格式正确 |
|||
|
|||
2. **认证失败** |
|||
- 检查令牌格式 |
|||
- 验证密钥配置 |
|||
- 确认过期时间设置 |
|||
|
|||
3. **密钥轮换问题** |
|||
- 检查轮换间隔设置 |
|||
- 验证密钥生成逻辑 |
|||
- 确保缓存正确更新 |
|||
|
|||
4. **性能问题** |
|||
- 优化令牌验证 |
|||
- 使用适当的缓存策略 |
|||
- 控制令牌大小 |
@ -0,0 +1,23 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\CellularManagement.Domain\CellularManagement.Domain.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="FluentValidation" Version="11.9.0" /> |
|||
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" /> |
|||
<PackageReference Include="MediatR" Version="12.2.0" /> |
|||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" /> |
|||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" /> |
|||
<PackageReference Include="Swashbuckle.AspNetCore.Examples" Version="2.9.0" /> |
|||
<PackageReference Include="Swashbuckle.Examples" Version="4.1.0" /> |
|||
</ItemGroup> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net8.0</TargetFramework> |
|||
<ImplicitUsings>enable</ImplicitUsings> |
|||
<Nullable>enable</Nullable> |
|||
</PropertyGroup> |
|||
|
|||
</Project> |
@ -0,0 +1,21 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace CellularManagement.Application.Features.Auth.Commands.Login; |
|||
|
|||
/// <summary>
|
|||
/// 登录请求
|
|||
/// </summary>
|
|||
public class LoginRequest |
|||
{ |
|||
/// <summary>
|
|||
/// 用户名
|
|||
/// </summary>
|
|||
[Required(ErrorMessage = "用户名不能为空")] |
|||
public string UserName { get; set; } = string.Empty; |
|||
|
|||
/// <summary>
|
|||
/// 密码
|
|||
/// </summary>
|
|||
[Required(ErrorMessage = "密码不能为空")] |
|||
public string Password { get; set; } = string.Empty; |
|||
} |
@ -0,0 +1,45 @@ |
|||
using Swashbuckle.AspNetCore.Filters; |
|||
|
|||
namespace CellularManagement.Application.Features.Auth.Commands.Login; |
|||
|
|||
/// <summary>
|
|||
/// 登录请求示例
|
|||
/// </summary>
|
|||
public class LoginRequestExample : IExamplesProvider<LoginRequest> |
|||
{ |
|||
/// <summary>
|
|||
/// 获取示例
|
|||
/// </summary>
|
|||
/// <returns>登录请求示例</returns>
|
|||
public LoginRequest GetExamples() |
|||
{ |
|||
return new LoginRequest |
|||
{ |
|||
UserName = "zhangsan", |
|||
Password = "P@ssw0rd!" |
|||
}; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 登录请求示例提供者
|
|||
/// </summary>
|
|||
public class LoginRequestExamples : IMultipleExamplesProvider<LoginRequest> |
|||
{ |
|||
/// <summary>
|
|||
/// 获取示例
|
|||
/// </summary>
|
|||
/// <returns>登录请求示例集合</returns>
|
|||
public IEnumerable<SwaggerExample<LoginRequest>> GetExamples() |
|||
{ |
|||
yield return SwaggerExample.Create( |
|||
"默认用户", |
|||
"使用默认测试账号", |
|||
new LoginRequest |
|||
{ |
|||
UserName = "zhangsan", |
|||
Password = "P@ssw0rd!" |
|||
} |
|||
); |
|||
} |
|||
} |
Loading…
Reference in new issue