using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using SimpleTodoApiWithPg.Data; using SimpleTodoApiWithPg.Models; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; namespace SimpleTodoApiWithPg.UserService { // Services/UserService.cs public class UserServices { private readonly AppDbContext _dbContext; private readonly ILogger _logger; // 在服务构造函数中注入 private readonly IConfiguration _configuration; public UserServices(AppDbContext dbContext, IConfiguration configuration, ILogger logger) { _dbContext = dbContext; _logger = logger; _configuration = configuration; } //前更新用户接口,暂时未使用 public async Task, BadRequest>> PatchUserAsync(User user) { _logger.LogInformation("Attempting to patch user in UserService: {Username}", user.Username); var existingUser = await _dbContext.Users.FirstOrDefaultAsync(u => u.Username == user.Username); if (existingUser == null) { _logger.LogWarning("User '{Username}' not found during patch.", user.Username); return TypedResults.BadRequest("用户名不存在,登录失败!。"); } if (!BCrypt.Net.BCrypt.Verify(user.PasswordHash, existingUser.PasswordHash, true)) { _logger.LogWarning("Incorrect password for user '{Username}' during patch.", user.Username); return TypedResults.BadRequest("密码错误,请重新输入。"); } // 假设这里执行更新逻辑 // existingUser.SomeProperty = user.SomeProperty; // await _dbContext.SaveChangesAsync(); _logger.LogInformation("User '{Username}' patched successfully.", user.Username); return TypedResults.Ok(existingUser); } //获取所有用户接口 public async Task>, BadRequest>> GetUsersAsync() { var users = await _dbContext.Users.ToListAsync(); return TypedResults.Ok(users); } //根据id获取对应用户接口 public async Task, NotFound>> GetoneUserAsync(Guid id) { var user = await _dbContext.Users.FindAsync(id); if (user == null) { return TypedResults.NotFound($"要查询的id:{id}不存在"); } return TypedResults.Ok(user); } //用户注册接口 public async Task> RegisterAsync(RegisterRequest request) { var exuser = await _dbContext.Users.AnyAsync(u => u.Username == request.Username); if (exuser) { return ApiResponse.Fail($"用户名:{request.Username}已存在,注册失败!", 400); }; //if (request.Username.Length <5 || request.Email.Length < 5 ) { return ApiResponse.Fail($"用户名或邮箱不符合规范,注册失败!", 400);}; var password = RandomNumberGenerator.GetString("0123456789",15); var user = new User(); user.Username = request.Username; user.Email = request.Email; user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(password, 10, true); _dbContext.Users.Add(user); await _dbContext.SaveChangesAsync(); return ApiResponse.Ok(new RegisterResponse { Username = user.Username, Email = user.Email, Password = password, UserId = user.Id }); } //更新用户接口 public async Task, NotFound>> UpdateUserAsync(int id, UpdateUserRequest updateUser) { var existingUser = await _dbContext.Users.FindAsync(id); if (existingUser == null) { return TypedResults.NotFound($"要更新的用户id:{id}不存在!"); }; if (updateUser.Username != null) { existingUser.Username = updateUser.Username; } if (!string.IsNullOrEmpty(updateUser.NewPassword)) { existingUser.PasswordHash = BCrypt.Net.BCrypt.HashPassword(updateUser.NewPassword,10,true); } if (updateUser.Email != null) { existingUser.Email = updateUser.Email; } await _dbContext.SaveChangesAsync(); return TypedResults.Ok(existingUser); } //删除指定用户接口 public async Task, NotFound>> DeleteUserAsync(Guid id) { var existingUser = await _dbContext.Users.FindAsync(id); if (existingUser == null) { return TypedResults.NotFound($"指定要删除的用户:{id}不存在!"); } _dbContext.Users.Remove(existingUser); await _dbContext.SaveChangesAsync(); return TypedResults.Ok($"指定的用户:{existingUser.Username}删除成功!"); } //登录认证接口 public async Task> LoginAuthAsync(LoginRequest loginRequest) { var existingUser = await _dbContext.Users.FirstOrDefaultAsync(u => u.Username == loginRequest.Username); if (existingUser == null || !BCrypt.Net.BCrypt.Verify(loginRequest.Password, existingUser.PasswordHash, true)) { _logger.LogError("用户登录失败!{request}"," ---用户名: "+loginRequest.Username+" ---密码: "+loginRequest.Password); return ApiResponse.Fail("用户名或密码错误!",400); } // 1. 生成 JWT (Access Token) var accessTokenExpiration = DateTime.UtcNow.AddMinutes(1); // 访问令牌有效期15分钟 var accessToken = GenerateJwtToken(existingUser, accessTokenExpiration); // 2. 生成刷新令牌 var refreshToken = GenerateRefreshToken(); refreshToken.UserId = existingUser.Id; await _dbContext.RefreshTokens.AddAsync(refreshToken); // (可选但推荐) 清理该用户旧的、无效的刷新令牌 var oldRefreshTokens = await _dbContext.RefreshTokens .Where(rt => rt.UserId == existingUser.Id && (rt.Revoked != null || rt.Expires <= DateTime.UtcNow)) .ToListAsync(); _dbContext.RefreshTokens.RemoveRange(oldRefreshTokens); await _dbContext.SaveChangesAsync(); // 3. 返回令牌对 return ApiResponse.Ok(new AuthResponse { AccessToken = accessToken, RefreshToken = refreshToken.Token, AccessTokenExpiration = accessTokenExpiration }); } //创建令牌接口 public string GenerateJwtToken(User user, DateTime expires) { // 加载证书以获取私钥进行签名 var certPath = _configuration["Jwt:CertificatePath"]!; var certPassword = _configuration["Jwt:CertificatePassword"]!; var certificate = X509CertificateLoader.LoadPkcs12FromFile(certPath, certPassword,X509KeyStorageFlags.EphemeralKeySet); var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, user.Username), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()) }; var token = new JwtSecurityToken( issuer: _configuration["Jwt:Issuer"], audience: _configuration["Jwt:Audience"], claims: claims, expires: expires, // 使用证书的私钥通过 ECDSA-SHA256 算法进行签名 signingCredentials: new SigningCredentials(new ECDsaSecurityKey(certificate.GetECDsaPrivateKey()!), SecurityAlgorithms.EcdsaSha256) ); return new JwtSecurityTokenHandler().WriteToken(token); } //创建刷新令牌接口 public RefreshToken GenerateRefreshToken() { var randomNumber = new byte[64]; using var rng = RandomNumberGenerator.Create(); rng.GetBytes(randomNumber); return new RefreshToken { Token = Convert.ToBase64String(randomNumber), Expires = DateTime.UtcNow.AddDays(1), // 刷新令牌有效期7天 Created = DateTime.UtcNow }; } } }