Files
ASP.NET-CORE-web-test/UserService/UserService.cs
2025-10-10 16:02:38 +08:00

208 lines
8.8 KiB
C#

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<UserServices> _logger; // 在服务构造函数中注入
private readonly IConfiguration _configuration;
public UserServices(AppDbContext dbContext, IConfiguration configuration, ILogger<UserServices> logger)
{
_dbContext = dbContext;
_logger = logger;
_configuration = configuration;
}
//前更新用户接口,暂时未使用
public async Task<Results<Ok<User>, BadRequest<string>>> 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<Results<Ok<List<User>>, BadRequest<string>>> GetUsersAsync()
{
var users = await _dbContext.Users.ToListAsync();
return TypedResults.Ok(users);
}
//根据id获取对应用户接口
public async Task<Results<Ok<User>, NotFound<string>>> 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<ApiResponse<RegisterResponse>> RegisterAsync(RegisterRequest request)
{
var exuser = await _dbContext.Users.AnyAsync(u => u.Username == request.Username);
if (exuser) { return ApiResponse.Fail<RegisterResponse>($"用户名:{request.Username}已存在,注册失败!", 400); };
//if (request.Username.Length <5 || request.Email.Length < 5 ) { return ApiResponse.Fail<RegisterResponse>($"用户名或邮箱不符合规范,注册失败!", 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<RegisterResponse>(new RegisterResponse
{
Username = user.Username,
Email = user.Email,
Password = password,
UserId = user.Id
});
}
//更新用户接口
public async Task<Results<Ok<User>, NotFound<string>>> 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<Results<Ok<string>, NotFound<string>>> 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<ApiResponse<AuthResponse>> 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<AuthResponse>("用户名或密码错误!",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
};
}
}
}