245 lines
8.4 KiB
C#
Raw Normal View History

2026-02-28 12:11:09 +08:00
using YD_Event.Application.Auth.Dtos;
2026-05-14 15:27:16 +08:00
using YD_Event.Core.Options;
2026-04-07 13:10:11 +08:00
using YD_Event.Core.Enum;
2026-05-14 15:27:16 +08:00
using Microsoft.Extensions.Options;
2025-12-17 10:32:52 +08:00
2025-12-17 11:12:13 +08:00
namespace YD_Event.Application.Auth;
2025-12-17 10:32:52 +08:00
/// <summary>
/// 用户授权
/// </summary>
[AllowAnonymous]
public class AuthService : IDynamicApiController
{
private readonly ISqlSugarRepository<SysUser> _sysUseRepository;
2026-04-07 13:10:11 +08:00
private readonly ISqlSugarRepository<SysUserRole> _sysUserRoleRepository;
2025-12-17 10:32:52 +08:00
private readonly ICaptcha _captcha;
private readonly IIdGenerator _idGenerator;
private readonly IEasyCachingProvider _easyCachingProvider;
private readonly IHttpContextAccessor _httpContextAccessor;
2026-05-14 15:27:16 +08:00
private readonly IOptionsMonitor<RoleOptions> _roleOptionsMonitor;
2025-12-17 10:32:52 +08:00
public AuthService(ISqlSugarRepository<SysUser> sysUseRepository,
2026-04-07 13:10:11 +08:00
ISqlSugarRepository<SysUserRole> sysUserRoleRepository,
2025-12-17 10:32:52 +08:00
ICaptcha captcha,
IIdGenerator idGenerator,
IEasyCachingProvider easyCachingProvider,
2026-05-14 15:27:16 +08:00
IHttpContextAccessor httpContextAccessor,
IOptionsMonitor<RoleOptions> roleOptionsMonitor)
2025-12-17 10:32:52 +08:00
{
_sysUseRepository = sysUseRepository;
2026-04-07 13:10:11 +08:00
_sysUserRoleRepository = sysUserRoleRepository;
2025-12-17 10:32:52 +08:00
_captcha = captcha;
_idGenerator = idGenerator;
_easyCachingProvider = easyCachingProvider;
_httpContextAccessor = httpContextAccessor;
2026-05-14 15:27:16 +08:00
_roleOptionsMonitor = roleOptionsMonitor;
2025-12-17 10:32:52 +08:00
}
/// <summary>
/// 系统用户登录
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
2026-03-17 15:32:01 +08:00
[DisplayName("系统用户登录")]
2025-12-17 10:32:52 +08:00
[HttpPost]
public async Task SignIn(AdminLoginInput dto)
{
bool validate = _captcha.Validate(dto.Id, dto.Code);
if (!validate)
{
throw Oops.Bah("验证码错误");
}
string signInErrorCacheKey = $"login.error.{dto.Account}";
CacheValue<int> value = await _easyCachingProvider.GetAsync<int>(signInErrorCacheKey);
//5分钟内连续验证密码失败超过4次将限制用户尝试
2026-01-30 15:50:03 +08:00
if (value.HasValue && value.Value > 4)
2025-12-17 10:32:52 +08:00
{
throw Oops.Bah("由于您多次登录失败,系统已限制账户登录");
}
SysUser user = await _sysUseRepository.GetFirstAsync(x => x.Account == dto.Account);
if (user == null)
{
throw Oops.Bah("用户名或密码错误");
}
var context = _httpContextAccessor.HttpContext;
if (user.Status == AvailabilityStatus.Disable || (user.LockExpired.HasValue && DateTime.Now < user.LockExpired))
{
throw Oops.Bah("您的账号被锁定");
}
if (user.Password != MD5Encryption.Encrypt($"{_idGenerator.Encode(user.Id)}{dto.Password}"))
{
await _easyCachingProvider.SetAsync(signInErrorCacheKey, value.Value + 1, TimeSpan.FromMinutes(5));
throw Oops.Bah("用户名或密码错误");
}
long uniqueId = _idGenerator.NewLong();
string token = JWTEncryption.Encrypt(new Dictionary<string, object>()
{
[AuthClaimsConst.AuthIdKey] = user.Id,
[AuthClaimsConst.AccountKey] = user.Account,
[AuthClaimsConst.UuidKey] = uniqueId,
[AuthClaimsConst.AuthPlatformTypeKey] = AuthPlatformType.Manager
2026-04-04 22:09:43 +08:00
});
2025-12-17 10:32:52 +08:00
// 获取刷新 token
var refreshToken = JWTEncryption.GenerateRefreshToken(token);
// 设置响应报文头
context.SigninToSwagger(token);
context!.Response.Headers["access-token"] = token;
context.Response.Headers["x-access-token"] = refreshToken;
}
/// <summary>
/// 获取验证码
/// </summary>
/// <param name="id">验证码唯一id</param>
/// <returns></returns>
2026-03-17 15:32:01 +08:00
[DisplayName("获取验证码")]
2025-12-17 10:32:52 +08:00
[HttpGet]
public IActionResult Captcha([FromQuery] string id)
{
var data = _captcha.Generate(id);
var stream = new MemoryStream(data.Bytes);
return new FileStreamResult(stream, "image/gif");
}
2026-02-28 12:11:09 +08:00
2026-04-07 13:10:11 +08:00
/// <summary>
/// 用户注册
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[DisplayName("用户注册")]
[HttpPost]
[UnitOfWork]
public async Task Register(RegisterInput dto)
{
var codeCacheKey = $"sms:code:{dto.Phone}";
var cachedCode = await _easyCachingProvider.GetAsync<string>(codeCacheKey);
if (!cachedCode.HasValue || cachedCode.Value != dto.Code)
{
throw Oops.Bah("验证码错误或已过期");
}
var existPhone = await _sysUseRepository.IsAnyAsync(x => x.Mobile == dto.Phone);
if (existPhone)
{
throw Oops.Bah("该手机号已被注册");
}
var user = new SysUser
{
Id = _idGenerator.NewLong(),
2026-04-14 17:30:20 +08:00
Account = dto.Phone,
Name = dto.Phone,
2026-04-07 13:10:11 +08:00
Mobile = dto.Phone,
Gender = Gender.Unknown,
OrgId = 0,
Status = AvailabilityStatus.Enable,
DeleteMark = false,
CreatedTime = DateTime.Now,
CreatedUserId = 0
};
user.Password = MD5Encryption.Encrypt($"{_idGenerator.Encode(user.Id)}{dto.Password}");
await _sysUseRepository.InsertAsync(user);
2026-05-14 15:27:16 +08:00
// 为新用户分配单位用户角色
2026-04-07 13:10:11 +08:00
var userRole = new SysUserRole
{
Id = _idGenerator.NewLong(),
UserId = user.Id,
2026-05-14 15:27:16 +08:00
RoleId = _roleOptionsMonitor.CurrentValue.UnitUserRoleId,
2026-04-07 13:10:11 +08:00
CreatedTime = DateTime.Now,
CreatedUserId = 0,
DeleteMark = false
};
await _sysUserRoleRepository.InsertAsync(userRole);
2026-02-28 12:11:09 +08:00
2026-04-07 13:10:11 +08:00
await _easyCachingProvider.RemoveAsync(codeCacheKey);
}
/// <summary>
/// 短信验证码登录
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[DisplayName("短信验证码登录")]
[HttpPost]
public async Task SmsSignIn(SmsLoginInput dto)
{
var codeCacheKey = $"sms:code:{dto.Phone}";
var cachedCode = await _easyCachingProvider.GetAsync<string>(codeCacheKey);
if (!cachedCode.HasValue || cachedCode.Value != dto.Code)
{
throw Oops.Bah("验证码错误或已过期");
}
SysUser user = await _sysUseRepository.GetFirstAsync(x => x.Mobile == dto.Phone);
if (user == null)
{
throw Oops.Bah("该手机号尚未注册");
}
var context = _httpContextAccessor.HttpContext;
if (user.Status == AvailabilityStatus.Disable || (user.LockExpired.HasValue && DateTime.Now < user.LockExpired))
{
throw Oops.Bah("您的账号被锁定");
}
long uniqueId = _idGenerator.NewLong();
string token = JWTEncryption.Encrypt(new Dictionary<string, object>()
{
[AuthClaimsConst.AuthIdKey] = user.Id,
[AuthClaimsConst.AccountKey] = user.Account,
[AuthClaimsConst.UuidKey] = uniqueId,
[AuthClaimsConst.AuthPlatformTypeKey] = AuthPlatformType.Manager
});
var refreshToken = JWTEncryption.GenerateRefreshToken(token);
context.SigninToSwagger(token);
context!.Response.Headers["access-token"] = token;
context.Response.Headers["x-access-token"] = refreshToken;
await _easyCachingProvider.RemoveAsync(codeCacheKey);
}
/// <summary>
/// 重置密码
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[DisplayName("重置密码")]
[HttpPost]
public async Task ResetPassword(ResetPasswordInput dto)
{
var codeCacheKey = $"sms:code:{dto.Phone}";
var cachedCode = await _easyCachingProvider.GetAsync<string>(codeCacheKey);
if (!cachedCode.HasValue || cachedCode.Value != dto.Code)
{
throw Oops.Bah("验证码错误或已过期");
}
SysUser user = await _sysUseRepository.GetFirstAsync(x => x.Mobile == dto.Phone);
if (user == null)
{
throw Oops.Bah("该手机号尚未注册");
}
if (user.Status == AvailabilityStatus.Disable || (user.LockExpired.HasValue && DateTime.Now < user.LockExpired))
{
throw Oops.Bah("您的账号被锁定");
}
user.Password = MD5Encryption.Encrypt($"{_idGenerator.Encode(user.Id)}{dto.NewPassword}");
user.UpdatedTime = DateTime.Now;
await _sysUseRepository.UpdateAsync(user);
await _easyCachingProvider.RemoveAsync(codeCacheKey);
}
}