Files
emall-api/FutureMailAPI/Services/AuthService.cs
2025-10-16 15:21:52 +08:00

157 lines
5.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using FutureMailAPI.Helpers;
using FutureMailAPI.DTOs;
using FutureMailAPI.Models;
using FutureMailAPI.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
namespace FutureMailAPI.Services
{
public interface IAuthService
{
Task<ApiResponse<AuthResponseDto>> LoginAsync(UserLoginDto loginDto);
Task<ApiResponse<AuthResponseDto>> RegisterAsync(UserRegisterDto registerDto);
}
public class AuthService : IAuthService
{
private readonly IUserService _userService;
private readonly IPasswordHelper _passwordHelper;
private readonly FutureMailDbContext _context;
private readonly IConfiguration _configuration;
public AuthService(
IUserService userService,
IPasswordHelper passwordHelper,
FutureMailDbContext context,
IConfiguration configuration)
{
_userService = userService;
_passwordHelper = passwordHelper;
_context = context;
_configuration = configuration;
}
public async Task<ApiResponse<AuthResponseDto>> LoginAsync(UserLoginDto loginDto)
{
// 获取用户信息
var userResult = await _userService.GetUserByUsernameOrEmailAsync(loginDto.UsernameOrEmail);
if (!userResult.Success || userResult.Data == null)
{
return ApiResponse<AuthResponseDto>.ErrorResult("用户名或密码错误");
}
var userDto = userResult.Data;
// 获取原始用户信息用于密码验证
var user = await _context.Users
.FirstOrDefaultAsync(u => u.Id == userDto.Id);
if (user == null)
{
return ApiResponse<AuthResponseDto>.ErrorResult("用户不存在");
}
// 验证密码
if (!_passwordHelper.VerifyPassword(loginDto.Password, user.PasswordHash, user.Salt))
{
return ApiResponse<AuthResponseDto>.ErrorResult("用户名或密码错误");
}
// 更新用户响应DTO
userDto.LastLoginAt = DateTime.UtcNow;
// 生成JWT令牌
var token = GenerateJwtToken(user);
var refreshToken = GenerateRefreshToken();
// 保存刷新令牌到用户表
user.RefreshToken = refreshToken;
user.RefreshTokenExpiryTime = DateTime.UtcNow.AddDays(7); // 刷新令牌7天过期
await _context.SaveChangesAsync();
// 创建认证响应DTO
var authResponse = new AuthResponseDto
{
User = userDto,
Token = token,
RefreshToken = refreshToken,
ExpiresIn = 3600 // 1小时单位秒
};
return ApiResponse<AuthResponseDto>.SuccessResult(authResponse, "登录成功");
}
public async Task<ApiResponse<AuthResponseDto>> RegisterAsync(UserRegisterDto registerDto)
{
// 检查用户名是否已存在
var existingUserResult = await _userService.GetUserByUsernameAsync(registerDto.Username);
if (existingUserResult.Success && existingUserResult.Data != null)
{
return ApiResponse<AuthResponseDto>.ErrorResult("用户名已存在");
}
// 检查邮箱是否已存在
var existingEmailResult = await _userService.GetUserByEmailAsync(registerDto.Email);
if (existingEmailResult.Success && existingEmailResult.Data != null)
{
return ApiResponse<AuthResponseDto>.ErrorResult("邮箱已被注册");
}
// 创建用户
var createUserResult = await _userService.CreateUserAsync(registerDto);
if (!createUserResult.Success)
{
return ApiResponse<AuthResponseDto>.ErrorResult(createUserResult.Message ?? "注册失败");
}
// 注册成功后,自动登录
var loginDto = new UserLoginDto
{
UsernameOrEmail = registerDto.Username,
Password = registerDto.Password
};
return await LoginAsync(loginDto);
}
private string GenerateJwtToken(User user)
{
var jwtSettings = _configuration.GetSection("Jwt");
var key = Encoding.ASCII.GetBytes(jwtSettings["Key"] ?? throw new InvalidOperationException("JWT密钥未配置"));
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
new Claim(ClaimTypes.Email, user.Email)
}),
Expires = DateTime.UtcNow.AddHours(1),
Issuer = jwtSettings["Issuer"],
Audience = jwtSettings["Audience"],
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
private string GenerateRefreshToken()
{
var randomNumber = new byte[32];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomNumber);
return Convert.ToBase64String(randomNumber);
}
}
}