Minimal API认证端点类重构:移除WebApplicationBuilder报错解决
重构JWT Token端点以移除WebApplicationBuilder依赖
问题背景
原本在Program.cs中实现的JWT Token获取端点,迁移到SecurityEndpoints静态类后,因在GetToken方法中依赖WebApplicationBuilder引发InvalidOperationException,需要重构移除该依赖并正确获取JWT配置项。
方案一:直接注入IConfiguration获取配置
IConfiguration已经默认注册到ASP.NET Core的DI容器中,可直接在端点方法里注入使用,完全替代WebApplicationBuilder的配置读取能力:
public static class SecurityEndpoints { public static void MapSecurityEndpoints(this WebApplication app) { app.MapPost("/api/security/getToken", GetToken) .AllowAnonymous() .WithTags("Security"); app.MapPost("/api/security/createUser", CreateUser).AllowAnonymous(); } internal static async Task<IResult> GetToken( UserManager<IdentityUser> userMgr, [FromBody] UserLoginDTO user, IConfiguration config) { var identityUser = await userMgr.FindByEmailAsync(user.Email); if (identityUser == null || !await userMgr.CheckPasswordAsync(identityUser, user.Password)) { return Results.Unauthorized(); } // 从IConfiguration读取JWT配置 var issuer = config["Jwt:Issuer"]; var audience = config["Jwt:Audience"]; var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Jwt:Key"])); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); var claims = new List<Claim> { new Claim(ClaimTypes.Email, identityUser.Email), new Claim(ClaimTypes.GivenName, identityUser.UserName) }; // 建议添加Token过期时间,提升安全性 var token = new JwtSecurityToken( issuer: issuer, audience: audience, claims: claims, signingCredentials: credentials, expires: DateTime.UtcNow.AddHours(1) ); var stringToken = new JwtSecurityTokenHandler().WriteToken(token); return Results.Ok(stringToken); } // CreateUser方法实现... }
方案二:绑定配置到强类型类(更优雅的类型安全方案)
硬编码配置键容易出错,将JWT配置绑定到强类型类,既能获得类型提示,也方便后续维护:
- 定义JWT配置强类型类
public class JwtSettings { public string Issuer { get; set; } = string.Empty; public string Audience { get; set; } = string.Empty; public string Key { get; set; } = string.Empty; }
- 在Program.cs中注册配置绑定
// 将appsettings.json中的Jwt节点绑定到JwtSettings类,并注册到DI容器 builder.Services.Configure<JwtSettings>(builder.Configuration.GetSection("Jwt"));
- 修改GetToken方法注入IOptions
internal static async Task<IResult> GetToken( UserManager<IdentityUser> userMgr, [FromBody] UserLoginDTO user, IOptions<JwtSettings> jwtSettings) { var settings = jwtSettings.Value; var identityUser = await userMgr.FindByEmailAsync(user.Email); if (identityUser == null || !await userMgr.CheckPasswordAsync(identityUser, user.Password)) { return Results.Unauthorized(); } var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(settings.Key)); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); var claims = new List<Claim> { new Claim(ClaimTypes.Email, identityUser.Email), new Claim(ClaimTypes.GivenName, identityUser.UserName) }; var token = new JwtSecurityToken( issuer: settings.Issuer, audience: settings.Audience, claims: claims, signingCredentials: credentials, expires: DateTime.UtcNow.AddHours(1) ); var stringToken = new JwtSecurityTokenHandler().WriteToken(token); return Results.Ok(stringToken); }
方案三:提取Token生成逻辑到独立服务(彻底解耦)
如果想让端点逻辑更简洁,同时便于单独测试Token生成逻辑,可以把这部分代码抽成独立服务:
- 定义Token服务接口
public interface ITokenService { string GenerateToken(IdentityUser user); }
- 实现Token服务
public class TokenService : ITokenService { private readonly JwtSettings _jwtSettings; public TokenService(IOptions<JwtSettings> jwtSettings) { _jwtSettings = jwtSettings.Value; } public string GenerateToken(IdentityUser user) { var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.Key)); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); var claims = new List<Claim> { new Claim(ClaimTypes.Email, user.Email), new Claim(ClaimTypes.GivenName, user.UserName) }; var token = new JwtSecurityToken( issuer: _jwtSettings.Issuer, audience: _jwtSettings.Audience, claims: claims, signingCredentials: credentials, expires: DateTime.UtcNow.AddHours(1) ); return new JwtSecurityTokenHandler().WriteToken(token); } }
- 在Program.cs中注册服务
builder.Services.AddScoped<ITokenService, TokenService>();
- 简化GetToken方法
internal static async Task<IResult> GetToken( UserManager<IdentityUser> userMgr, [FromBody] UserLoginDTO user, ITokenService tokenService) { var identityUser = await userMgr.FindByEmailAsync(user.Email); if (identityUser == null || !await userMgr.CheckPasswordAsync(identityUser, user.Password)) { return Results.Unauthorized(); } var token = tokenService.GenerateToken(identityUser); return Results.Ok(token); }
内容的提问来源于stack exchange,提问作者pușigreen
相关产品推荐
相关产品推荐

