.NET桌面应用(WPF/WinUI3)通过本地独立账户认证Web API
基于本地ASP.NET Identity的跨端认证实现方案
核心思路是搭建自定义JWT认证体系,复用本地ASP.NET Identity的用户数据,让Windows桌面应用通过用户名密码登录获取JWT令牌,后续API调用携带令牌完成身份验证,完全脱离Azure/Entra依赖。
1. 配置Web API的Identity与JWT认证
先在Web API项目中完成基础配置,集成本地Identity并启用JWT认证:
1.1 服务配置(Program.cs)
// 配置本地数据库与ASP.NET Identity builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>(); // 配置JWT认证参数 var jwtSettings = builder.Configuration.GetSection("JwtSettings"); builder.Services.AddAuthentication(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(); // 注册中间件(注意顺序) app.UseAuthentication(); app.UseAuthorization();
1.2 JWT配置(appsettings.json)
"JwtSettings": { "Issuer": "YourWebApiDomain", "Audience": "YourWebApiAudience", "SecretKey": "YourStrongSecretKeyAtLeast16Characters", "TokenExpirationMinutes": 60 }
2. 添加桌面应用专属登录端点
在Web API中创建认证控制器,处理桌面应用的用户名密码登录请求并生成JWT令牌:
[ApiController] [Route("api/auth")] public class AuthController : ControllerBase { private readonly UserManager<IdentityUser> _userManager; private readonly IConfiguration _configuration; public AuthController(UserManager<IdentityUser> userManager, IConfiguration configuration) { _userManager = userManager; _configuration = configuration; } [HttpPost("login")] public async Task<IActionResult> Login([FromBody] LoginRequest request) { var user = await _userManager.FindByNameAsync(request.Username); if (user == null || !await _userManager.CheckPasswordAsync(user, request.Password)) { return Unauthorized("无效的用户名或密码"); } var token = GenerateJwtToken(user); return Ok(new { Token = token }); } private string GenerateJwtToken(IdentityUser user) { var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, user.Id), new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtSettings:SecretKey"])); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: _configuration["JwtSettings:Issuer"], audience: _configuration["JwtSettings:Audience"], claims: claims, expires: DateTime.Now.AddMinutes(Convert.ToDouble(_configuration["JwtSettings:TokenExpirationMinutes"])), signingCredentials: creds); return new JwtSecurityTokenHandler().WriteToken(token); } public class LoginRequest { public string Username { get; set; } public string Password { get; set; } } }
3. Windows桌面应用实现认证与API调用
以WPF为例,通过HttpClient完成登录获取令牌,后续API请求携带令牌:
// 获取JWT令牌 private async Task<string> GetAuthToken(string username, string password) { using var client = new HttpClient(); var loginRequest = new { Username = username, Password = password }; var json = JsonSerializer.Serialize(loginRequest); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await client.PostAsync("https://your-web-api-domain/api/auth/login", content); if (!response.IsSuccessStatusCode) { throw new Exception($"登录失败: {await response.Content.ReadAsStringAsync()}"); } var result = await response.Content.ReadFromJsonAsync<LoginResult>(); return result.Token; } // 调用受保护的API private async Task CallProtectedApi(string token) { using var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); var response = await client.GetAsync("https://your-web-api-domain/api/protected-resource"); if (response.IsSuccessStatusCode) { var data = await response.Content.ReadAsStringAsync(); // 处理返回数据 } else { // 处理未授权或请求错误 } } // 辅助模型 public class LoginResult { public string Token { get; set; } }
4. 额外优化建议
- 令牌刷新:添加刷新令牌机制,生成JWT时同步生成刷新令牌存入数据库,桌面应用可通过刷新令牌获取新的访问令牌,避免频繁登录。
- 传输安全:确保所有请求使用HTTPS,防止密码和令牌明文泄露。
- 权限控制:在JWT中添加角色/自定义声明,API端通过
[Authorize(Roles = "Admin")]或自定义策略实现细粒度权限控制。
内容的提问来源于stack exchange,提问作者Martin Robins
相关产品推荐
相关产品推荐

