Files

180 lines
6.7 KiB
C#
Raw Permalink Normal View History

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<AdminUser> adminUserRepository,
IAdminPermissionService adminPermissionService,
IConfiguration configuration,
ILogger<AdminAuthService> logger) : BaseRepository<AdminUser>, IAdminAuthService
{
private const string TokenKeyPrefix = "InteractiveMagazine:AdminAuth:Token";
private const string UserInfoKeyPrefix = "InteractiveMagazine:AdminAuth:UserInfo";
public async Task<AdminLoginOutput> 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<AdminUserInfoOutput> 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<JwtSettings>()
?? 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;
}
}