一文读懂 .NET 鉴权系统模块设计与代码实现
·

**第一部分:核心概念与架构设计 **
1.1 认证 vs 授权
- 认证 (Authentication): 验证用户身份(如用户名密码、社交登录、证书)
- 授权 (Authorization): 验证用户是否有权限执行操作(如角色检查、策略验证)
1.2 核心协议与标准
- OAuth 2.0: 授权框架(授权码、客户端凭证等流程)
- OpenID Connect (OIDC): 基于OAuth 2.0的身份层(提供用户信息端点)
- JWT (JSON Web Token): 轻量级自包含令牌格式(Header.Payload.Signature)
1.3 现代 .NET 鉴权架构分层
+-----------------------+
| 应用层 (API/MVC) |
| - [Authorize] 特性 |
| - 用户上下文访问 |
+-----------------------+
↓
+-----------------------+
| 鉴权中间件层 |
| - 认证处理器 (Authentication) |
| - 授权策略 (Authorization) |
+-----------------------+
↓
+-----------------------+
| 身份管理服务层 |
| - 用户存储 (ASP.NET Identity)|
| - 外部登录提供程序 |
+-----------------------+
↓
+-----------------------+
| 令牌服务层 (可选) |
| - JWT 签发/验证 |
| - Refresh Token 管理 |
+-----------------------+
↓
+-----------------------+
| 持久化存储层 |
| - 数据库 (SQL/NoSQL) |
| - 分布式缓存 (Redis) |
+-----------------------+
1.4 关键模块设计
- 用户管理模块:注册、登录、资料管理、双因素认证
- 认证模块:凭证验证、外部登录集成、令牌颁发
- 授权模块:角色/声明/策略管理、资源保护
- 令牌管理模块:JWT生命周期管理、Refresh Token轮换
- 审计与日志模块:关键操作日志记录
**第二部分:代码实现详解 **
2.1 项目初始化与基础配置
dotnet new webapi -n AuthDemo
cd AuthDemo
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
Program.cs 基础配置
var builder = WebApplication.CreateBuilder(args);
// 添加数据库上下文 (Identity)
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
// 配置Identity核心服务
builder.Services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders();
// 配置JWT认证
var jwtSettings = builder.Configuration.GetSection("Jwt");
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings["Issuer"],
ValidAudience = jwtSettings["Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(jwtSettings["SecretKey"]))
};
});
// 配置授权策略示例
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdmin", policy =>
policy.RequireRole("Admin"));
options.AddPolicy("Over18", policy =>
policy.RequireClaim("Age", "18"));
});
builder.Services.AddControllers();
2.2 用户管理模块实现
自定义用户模型 (扩展IdentityUser)
public class ApplicationUser : IdentityUser
{
public DateTime DateOfBirth { get; set; }
public string? CustomTag { get; set; }
}
用户注册API
[ApiController]
[Route("api/[controller]")]
public class AccountController : ControllerBase
{
private readonly UserManager<ApplicationUser> _userManager;
public AccountController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
[HttpPost("register")]
public async Task<IActionResult> Register(RegisterModel model)
{
var user = new ApplicationUser
{
UserName = model.Email,
Email = model.Email,
DateOfBirth = model.DateOfBirth
};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// 添加默认角色(示例)
await _userManager.AddToRoleAsync(user, "User");
return Ok(new { Message = "注册成功" });
}
return BadRequest(result.Errors);
}
}
2.3 认证模块:JWT令牌服务
TokenService.cs
public class TokenService
{
private readonly IConfiguration _configuration;
private readonly UserManager<ApplicationUser> _userManager;
public TokenService(IConfiguration configuration, UserManager<ApplicationUser> userManager)
{
_configuration = configuration;
_userManager = userManager;
}
public async Task<string> GenerateJwtToken(ApplicationUser user)
{
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, user.Id),
new Claim(JwtRegisteredClaimNames.Email, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim("dob", user.DateOfBirth.ToString("yyyy-MM-dd"))
};
// 添加用户角色声明
var roles = await _userManager.GetRolesAsync(user);
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
var key = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _configuration["Jwt:Issuer"],
audience: _configuration["Jwt:Audience"],
claims: claims,
expires: DateTime.UtcNow.AddMinutes(30), // 短生命周期Access Token
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
登录API(含Refresh Token)
[HttpPost("login")]
public async Task<IActionResult> Login(LoginModel model)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user == null || !await _userManager.CheckPasswordAsync(user, model.Password))
return Unauthorized();
var accessToken = await _tokenService.GenerateJwtToken(user);
var refreshToken = GenerateRefreshToken();
// 保存Refresh Token到数据库(需实现)
await SaveRefreshTokenAsync(user.Id, refreshToken);
return Ok(new
{
AccessToken = accessToken,
RefreshToken = refreshToken,
ExpiresIn = 1800 // 30分钟
});
}
private string GenerateRefreshToken()
{
var randomNumber = new byte[32];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomNumber);
return Convert.ToBase64String(randomNumber);
}
2.4 授权模块:高级策略控制
自定义策略提供程序
// 要求用户拥有特定权限代码
public class PermissionRequirement : IAuthorizationRequirement
{
public string Permission { get; }
public PermissionRequirement(string permission) => Permission = permission;
}
public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
PermissionRequirement requirement)
{
if (context.User.HasClaim(c =>
c.Type == "permissions" &&
c.Value == requirement.Permission))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
// 注册策略
services.AddAuthorization(options =>
{
options.AddPolicy("DeleteProduct", policy =>
policy.Requirements.Add(new PermissionRequirement("product.delete")));
});
services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
资源级授权(使用IAuthorizationService)
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProduct(int id)
{
var product = await _productService.GetProductById(id);
var authResult = await _authorizationService.AuthorizeAsync(
User, product, "DeleteProduct");
if (!authResult.Succeeded)
return Forbid();
await _productService.DeleteProduct(id);
return NoContent();
}
2.5 令牌管理模块
Refresh Token端点
[HttpPost("refresh")]
public async Task<IActionResult> RefreshToken(RefreshTokenModel model)
{
var principal = GetPrincipalFromExpiredToken(model.AccessToken);
var userId = principal.FindFirstValue(ClaimTypes.NameIdentifier);
var user = await _userManager.FindByIdAsync(userId);
if (user == null || !ValidateRefreshToken(userId, model.RefreshToken))
return BadRequest("无效令牌");
var newAccessToken = await _tokenService.GenerateJwtToken(user);
var newRefreshToken = GenerateRefreshToken();
// 更新Refresh Token(使旧Token失效)
await UpdateRefreshTokenAsync(userId, model.RefreshToken, newRefreshToken);
return Ok(new {
AccessToken = newAccessToken,
RefreshToken = newRefreshToken
});
}
令牌吊销实现
// 在认证选项中添加事件处理
.AddJwtBearer(options =>
{
options.Events = new JwtBearerEvents
{
OnTokenValidated = async context =>
{
var token = context.SecurityToken as JwtSecurityToken;
var jti = token?.Claims.First(c => c.Type == JwtRegisteredClaimNames.Jti).Value;
if (await IsTokenRevoked(jti))
{
context.Fail("令牌已被吊销");
}
}
};
});
// 吊销API
[HttpPost("revoke")]
[Authorize]
public async Task<IActionResult> RevokeToken()
{
var jti = User.FindFirst(JwtRegisteredClaimNames.Jti)?.Value;
await _tokenStore.RevokeTokenAsync(jti);
return NoContent();
}
2.6 安全加固实践
- HTTPS强制: 生产环境强制HTTPS
app.UseHttpsRedirection(); - Cookie安全配置:
services.ConfigureApplicationCookie(options => { options.Cookie.HttpOnly = true; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; options.SlidingExpiration = true; }); - JWT最佳实践:
- 使用强密钥(256位+)
- 设置合理短的有效期(Access Token: 15-30分钟)
- JWT存储在内存中,避免localStorage
- 防暴力破解:
services.Configure<IdentityOptions>(options => { options.Lockout.MaxFailedAccessAttempts = 5; options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15); });
**第三部分:进阶方案与扩展 **
3.1 多租户架构下的鉴权
- 租户识别策略:
- 子域名解析 (
tenant1.app.com) - 请求头 (
X-Tenant-Id) - JWT中的租户声明
- 子域名解析 (
- 数据库隔离方案:
services.AddDbContext<AppDbContext>((provider, options) => { var tenantService = provider.GetService<ITenantService>(); options.UseSqlServer(tenantService.GetConnectionString()); });
3.2 第三方登录集成
Google登录配置示例
services.AddAuthentication()
.AddGoogle(options =>
{
options.ClientId = config["Google:ClientId"];
options.ClientSecret = config["Google:ClientSecret"];
options.CallbackPath = "/signin-google";
});
处理外部登录回调
[HttpGet("ExternalLoginCallback")]
public async Task<IActionResult> ExternalLoginCallback()
{
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null) return RedirectToAction("Login");
// 关联现有账户或创建新用户
var user = await _userManager.FindByEmailAsync(info.Principal.FindFirstValue(ClaimTypes.Email));
if (user == null)
{
user = new ApplicationUser { UserName = info.Principal.Identity.Name, ... };
await _userManager.CreateAsync(user);
}
await _userManager.AddLoginAsync(user, info);
await _signInManager.SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
3.3 微服务架构的分布式鉴权
- API网关统一认证:
- 在网关层验证JWT
- 将用户声明转发给下游服务(通过Headers)
- OAuth 2.0 Token Introspection:
services.AddAuthentication("Introspection") .AddOAuth2Introspection(options => { options.Authority = "https://auth-server"; options.ClientId = "api-resource"; options.ClientSecret = "secret"; }); - 使用IdentityServer4/OpenIddict: 搭建专业授权服务器
3.4 性能优化策略
- JWT签名算法选择: 使用非对称算法(如RS256)减轻API服务器压力
- 分布式缓存: 缓存用户信息、权限数据(Redis)
services.AddStackExchangeRedisCache(options => { options.Configuration = "localhost:6379"; }); - 声明精简: 避免在JWT中存储过多数据
- 批处理授权检查: 减少数据库查询次数
**第四部分:监控、测试与部署 **
4.1 关键监控指标
- 认证成功率/失败率
- 授权失败次数(按端点分类)
- Token签发频率
- 并发会话数
- 密码重置请求量
4.2 安全测试要点
- OWASP Top 10 相关测试:
- 失效的访问控制(Broken Access Control)
- 身份验证失效(Broken Authentication)
- 安全配置错误(Security Misconfiguration)
- 渗透测试项目:
- JWT篡改测试
- Token重放攻击
- CSRF/XSS攻击尝试
- 暴力破解模拟
4.3 部署注意事项
- 密钥管理:
- 使用Azure Key Vault/AWS KMS管理密钥
- 禁止硬编码密钥
- 环境隔离: 测试/生产环境使用独立证书和密钥
- 紧急响应:
- 预设令牌吊销流程
- 保留用户会话强制下线能力
- 合规性检查: 确保符合GDPR、CCPA等法规要求
结语:构建健壮鉴权系统的关键原则
- 最小权限原则: 用户只拥有完成工作所需的最小权限
- 纵深防御: 多层安全措施(网络/应用/数据层)
- 零信任架构: 永不信任,始终验证
- 安全默认值: 框架默认启用安全配置
- 持续审计: 定期审查权限分配和访问日志

更多推荐


所有评论(0)