Files
QYZH.InteractiveMagazine/QYZH.InteractiveMagazine.Service/AdminAuthService.cs
glz 8ed012bba8 refactor: 重构项目基础架构与实体体系
- 替换原有自定义生命周期接口为通用基础服务体系
- 将所有实体基类替换为带雪花ID的SqlSugarBaseEntity
- 迁移DTO到Models项目并统一管理
- 移除冗余的Repository层实现,改用通用基础服务
- 添加Yitter.IdGenerator雪花ID生成支持
- 重构SqlSugar数据库上下文与依赖注入配置
- 新增微信用户、用户勋章、背包等实体与配套服务
- 整理分页查询与结果封装类
- 优化WebApi控制器结构
2026-06-02 14:10:43 +08:00

161 lines
5.7 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 BCrypt.Net;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using QYZH.InteractiveMagazine.Infrastructure.Auth;
using QYZH.InteractiveMagazine.Infrastructure.Cache;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.IService.Dto;
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, 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("用户名不能为空", 400);
}
if (string.IsNullOrWhiteSpace(input.Password))
{
throw new BusinessException("密码不能为空", 400);
}
var adminUser = await adminUserRepository.GetFirstAsync(a => a.UserName == input.UserName);
if (adminUser == null)
{
logger.LogWarning("管理员登录失败,用户名不存在: {UserName}", input.UserName);
throw new BusinessException("用户名或密码错误", 401);
}
if (!BCrypt.Net.BCrypt.Verify(input.Password, adminUser.PasswordHash))
{
logger.LogWarning("管理员登录失败,密码错误: {UserName}", input.UserName);
throw new BusinessException("用户名或密码错误", 401);
}
if (adminUser.Status != "Active")
{
logger.LogWarning("管理员登录失败,账号已禁用: {UserName}", input.UserName);
throw new BusinessException("账号已被禁用,请联系系统管理员", 403);
}
var jwtSettings = GetJwtSettings();
var token = JwtHelper.GenerateToken((long)adminUser.Id, adminUser.UserName, jwtSettings);
await RedisHelper.StringSetAsync($"{TokenKeyPrefix}:{adminUser.Id}", token, TimeSpan.FromMinutes(jwtSettings.ExpiryMinutes));
logger.LogInformation("管理员登录成功,用户名: {UserName}, ID: {UserId}", input.UserName, adminUser.Id);
return new AdminLoginOutput
{
Token = token,
UserId = (long)adminUser.Id,
UserName = adminUser.UserName,
Type = adminUser.Type
};
}
public async Task LogoutAsync(long userId)
{
logger.LogInformation("管理员登出ID: {UserId}", userId);
await RedisHelper.KeyDeleteAsync($"{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("用户不存在", 404);
}
return new AdminUserInfoOutput
{
UserId = adminUser.Id,
UserName = adminUser.UserName,
Type = adminUser.Type,
Status = adminUser.Status
};
}
public async Task ChangePasswordAsync(long userId, string oldPassword, string newPassword)
{
logger.LogInformation("管理员修改密码尝试ID: {UserId}", userId);
if (string.IsNullOrWhiteSpace(oldPassword))
{
throw new BusinessException("原密码不能为空", 400);
}
if (string.IsNullOrWhiteSpace(newPassword))
{
throw new BusinessException("新密码不能为空", 400);
}
var adminUser = await adminUserRepository.GetByIdAsync(userId);
if (adminUser == null)
{
logger.LogWarning("未找到管理员ID: {UserId}", userId);
throw new BusinessException("用户不存在", 404);
}
if (!BCrypt.Net.BCrypt.Verify(oldPassword, adminUser.PasswordHash))
{
logger.LogWarning("管理员修改密码失败原密码错误ID: {UserId}", userId);
throw new BusinessException("原密码错误", 400);
}
adminUser.PasswordHash = BCrypt.Net.BCrypt.HashPassword(newPassword);
var result = await adminUserRepository.UpdateAsync(adminUser);
if (!result)
{
throw new BusinessException("修改密码失败", 500);
}
await RedisHelper.KeyDeleteAsync($"{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 配置不完整", 500);
}
return jwtSettings;
}
}