using BCrypt.Net; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using QYZH.InteractiveMagazine.Infrastructure.Auth; using QYZH.InteractiveMagazine.IService; using QYZH.InteractiveMagazine.Models.Common; using QYZH.InteractiveMagazine.Models.Dto; using QYZH.InteractiveMagazine.Models.Entity; using QYZH.InteractiveMagazine.Models.Settings; using QYZH.InteractiveMagazine.Repository; namespace QYZH.InteractiveMagazine.Service; public class AdminAuthService( BaseRepository adminUserRepository, IAdminPermissionService adminPermissionService, IConfiguration configuration, ILogger logger) : BaseRepository, IAdminAuthService { private const string TokenKeyPrefix = "InteractiveMagazine:AdminAuth:Token"; private const string UserInfoKeyPrefix = "InteractiveMagazine:AdminAuth:UserInfo"; public async Task LoginAsync(AdminLoginInput input) { logger.LogInformation("管理员登录尝试,用户名: {UserName}", input.UserName); if (string.IsNullOrWhiteSpace(input.UserName)) { throw new BusinessException("用户名不能为空", ResultCode.BAD_REQUEST); } if (string.IsNullOrWhiteSpace(input.Password)) { throw new BusinessException("密码不能为空", ResultCode.BAD_REQUEST); } var adminUser = await adminUserRepository.GetFirstAsync(a => a.UserName == input.UserName); if (adminUser == null) { logger.LogWarning("管理员登录失败,用户名不存在: {UserName}", input.UserName); throw new BusinessException("用户名或密码错误", ResultCode.DENY); } if (!BCrypt.Net.BCrypt.Verify(input.Password, adminUser.PasswordHash)) { logger.LogWarning("管理员登录失败,密码错误: {UserName}", input.UserName); throw new BusinessException("用户名或密码错误", ResultCode.DENY); } if (adminUser.Status != 1) { logger.LogWarning("管理员登录失败,账号已禁用: {UserName}", input.UserName); throw new BusinessException("账号已被禁用,请联系系统管理员", ResultCode.FORBIDDEN); } var jwtSettings = GetJwtSettings(); var token = JwtHelper.GenerateToken((long)adminUser.Id, adminUser.UserName, jwtSettings); await RedisHelper.SetAsync($"{TokenKeyPrefix}:{adminUser.Id}", token, TimeSpan.FromMinutes(jwtSettings.ExpiryMinutes)); logger.LogInformation("管理员登录成功,用户名: {UserName}, ID: {UserId}", input.UserName, adminUser.Id); var roles = await adminPermissionService.GetAdminUserRolesAsync(adminUser.Id); var menus = await adminPermissionService.GetAdminUserMenuTreeAsync(adminUser.Id); var permissionCodes = await adminPermissionService.GetAdminUserPermissionCodesAsync(adminUser.Id); return new AdminLoginOutput { Token = token, UserId = (long)adminUser.Id, UserName = adminUser.UserName, Type = adminUser.Type.ToString(), RoleIds = roles.Select(x => x.Id).ToList(), Roles = roles, Menus = menus, PermissionCodes = permissionCodes }; } public async Task LogoutAsync(long userId) { logger.LogInformation("管理员登出,ID: {UserId}", userId); await RedisHelper.DelAsync($"{TokenKeyPrefix}:{userId}"); logger.LogInformation("管理员登出成功,ID: {UserId}", userId); } public async Task GetAdminInfoAsync(long userId) { logger.LogInformation("获取管理员信息,ID: {UserId}", userId); var adminUser = await adminUserRepository.GetByIdAsync(userId); if (adminUser == null) { logger.LogWarning("未找到管理员,ID: {UserId}", userId); throw new BusinessException("用户不存在", ResultCode.NOT_FOUND); } var roles = await adminPermissionService.GetAdminUserRolesAsync(adminUser.Id); var menus = await adminPermissionService.GetAdminUserMenuTreeAsync(adminUser.Id); var permissionCodes = await adminPermissionService.GetAdminUserPermissionCodesAsync(adminUser.Id); return new AdminUserInfoOutput { UserId = adminUser.Id, UserName = adminUser.UserName, Type = adminUser.Type.ToString(), Status = adminUser.Status, RoleIds = roles.Select(x => x.Id).ToList(), Roles = roles, Menus = menus, PermissionCodes = permissionCodes }; } public async Task ChangePasswordAsync(long userId, string oldPassword, string newPassword) { logger.LogInformation("管理员修改密码尝试,ID: {UserId}", userId); if (string.IsNullOrWhiteSpace(oldPassword)) { throw new BusinessException("原密码不能为空", ResultCode.BAD_REQUEST); } if (string.IsNullOrWhiteSpace(newPassword)) { throw new BusinessException("新密码不能为空", ResultCode.BAD_REQUEST); } var adminUser = await adminUserRepository.GetByIdAsync(userId); if (adminUser == null) { logger.LogWarning("未找到管理员,ID: {UserId}", userId); throw new BusinessException("用户不存在", ResultCode.NOT_FOUND); } if (!BCrypt.Net.BCrypt.Verify(oldPassword, adminUser.PasswordHash)) { logger.LogWarning("管理员修改密码失败,原密码错误,ID: {UserId}", userId); throw new BusinessException("原密码错误", ResultCode.DENY); } adminUser.PasswordHash = BCrypt.Net.BCrypt.HashPassword(newPassword); var result = await adminUserRepository.UpdateAsync(adminUser); if (!result) { throw new BusinessException("修改密码失败", ResultCode.GLOBAL_ERROR); } await RedisHelper.DelAsync($"{TokenKeyPrefix}:{userId}"); logger.LogInformation("管理员修改密码成功,ID: {UserId}", userId); } private JwtSettings GetJwtSettings() { var jwtSettings = configuration.GetSection("JwtSettings").Get() ?? new JwtSettings { Issuer = "QYZH.InteractiveMagazine", Audience = "QYZH.InteractiveMagazine", SecretKey = "your-256-bit-secret-key-here-change-in-production", ExpiryMinutes = 120 }; if (string.IsNullOrWhiteSpace(jwtSettings.SecretKey)) { throw new BusinessException("JWT 配置不完整", ResultCode.GLOBAL_ERROR); } return jwtSettings; } }