SysAuthService.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. using Furion.DatabaseAccessor.Extensions;
  2. using Furion.EventBus;
  3. using Microsoft.Extensions.Options;
  4. using UAParser;
  5. using YBEE.EQM.Core;
  6. namespace YBEE.EQM.Application;
  7. /// <summary>
  8. /// 认证服务
  9. /// </summary>
  10. public class SysAuthService(IOptions<AuthOptions> options,
  11. IHttpContextAccessor httpContextAccessor,
  12. IEventPublisher eventPublisher,
  13. IRepository<SysUser> userRep,
  14. ISysRoleUserService roleUserService,
  15. ISysMenuService menuService,
  16. IGeneralCaptchaService captchaService) : ISysAuthService, ITransient
  17. {
  18. private readonly AuthOptions _authOptions = options.Value;
  19. /// <summary>
  20. /// 登录处理
  21. /// </summary>
  22. /// <param name="accountLoginInput">账户密码</param>
  23. /// <returns></returns>
  24. private async Task<AuthOutput> Login(LoginInput accountLoginInput)
  25. {
  26. var checkCaptcha = captchaService.CheckCode(accountLoginInput.Captcha);
  27. if (checkCaptcha.Code != 0)
  28. {
  29. throw Oops.Oh(checkCaptcha.Message);
  30. }
  31. string pwd = "";
  32. string newPwd = "";
  33. try
  34. {
  35. pwd = RSAEncryption.Decrypt(accountLoginInput.Password, _authOptions.RsaPrivateKey);
  36. if (!string.IsNullOrEmpty(accountLoginInput.NewPassword))
  37. {
  38. newPwd = RSAEncryption.Decrypt(accountLoginInput.NewPassword, _authOptions.RsaPrivateKey);
  39. if (pwd == newPwd)
  40. {
  41. throw Oops.Oh(ErrorCode.E1009);
  42. }
  43. }
  44. }
  45. catch
  46. {
  47. throw Oops.Oh("密码格式错误!");
  48. }
  49. //// 判断用户名和密码是否正确 忽略全局过滤器
  50. //var users = await _userRep.DetachedEntities
  51. // .Include(t => t.SysOrg)
  52. // .Where(u => (u.Account.Equals(accountLoginInput.Account) || u.Mobile.Equals(accountLoginInput.Account) || u.Email.Equals(accountLoginInput.Account)) && u.IsDeleted == false)
  53. // .ToListAsync();
  54. var user = await userRep.Include(t => t.SysOrg)
  55. .FirstOrDefaultAsync(u => u.IsDeleted == false &&
  56. (u.Account.Equals(accountLoginInput.Account) ||
  57. u.Mobile.Equals(accountLoginInput.Account) ||
  58. u.Email.Equals(accountLoginInput.Account)
  59. )) ?? throw Oops.Oh(ErrorCode.E1001);
  60. //if (!AESEncryption.Decrypt(user.Password, _authOptions.AesPassword).Equals(pwd))
  61. if (!PBKDF2Encryption.Compare(pwd, user.Password))
  62. {
  63. throw Oops.Oh(ErrorCode.E1001);
  64. }
  65. //var user = (users?.FirstOrDefault(u => AESEncryption.Decrypt(u.Password, _authOptions.AesPassword).Equals(pwd))) ?? throw Oops.Oh(ErrorCode.E1001);
  66. if (!user.IsActivated && newPwd != "")
  67. {
  68. //user.Password = AESEncryption.Encrypt(newPwd, _authOptions.AesPassword);
  69. user.Password = PBKDF2Encryption.Encrypt(newPwd);
  70. user.IsActivated = true;
  71. user.ActivateTime = DateTime.Now;
  72. await user.UpdateIncludeNowAsync(new[] { nameof(user.Password), nameof(user.IsActivated), nameof(user.ActivateTime) });
  73. }
  74. AuthOutput ret = new()
  75. {
  76. OrgName = user.SysOrg.Name,
  77. Name = user.Name,
  78. Account = user.Account,
  79. IsActivated = user.IsActivated,
  80. AccessToken = "",
  81. };
  82. if (!user.IsActivated)
  83. {
  84. return ret;
  85. }
  86. // 验证账号是否被冻结
  87. if (user.Status == CommonStatus.DISABLE)
  88. {
  89. throw Oops.Oh(ErrorCode.E1003);
  90. }
  91. var isSuperAdmin = await roleUserService.IsSuperAdmin(user.Id);
  92. // 生成Token令牌
  93. var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
  94. {
  95. {ClaimConst.CLAINM_USERID, user.Id},
  96. {ClaimConst.CLAINM_ACCOUNT, user.Account},
  97. {ClaimConst.CLAINM_NAME, user.Name},
  98. {ClaimConst.CLAINM_ORGID, user.SysOrgId},
  99. {ClaimConst.CLAINM_ORGNAME, user.SysOrg.Name},
  100. {ClaimConst.CLAINM_SUPERADMIN, isSuperAdmin.ToString()},
  101. });
  102. // 设置Swagger自动登录
  103. httpContextAccessor.HttpContext.SigninToSwagger(accessToken);
  104. // 生成刷新Token令牌
  105. var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, App.GetOptions<RefreshTokenSettingOptions>().ExpiredTime);
  106. // 设置刷新Token令牌
  107. httpContextAccessor.HttpContext.Response.Headers["x-access-token"] = refreshToken;
  108. ret.AccessToken = accessToken;
  109. return ret;
  110. }
  111. /// <summary>
  112. /// 账户密码登录
  113. /// </summary>
  114. /// <param name="input"></param>
  115. /// <returns></returns>
  116. public async Task<AuthOutput> LoginByAccount([Required] LoginInput input)
  117. {
  118. return await Login(accountLoginInput: input);
  119. }
  120. /// <summary>
  121. /// 获取当前登录用户信息
  122. /// </summary>
  123. /// <returns></returns>
  124. public async Task<LoginOutput> GetLoginUser()
  125. {
  126. var user = await userRep.Include(t => t.SysOrg).FirstOrDefaultAsync(u => u.Id == CurrentSysUserInfo.SysUserId) ?? throw Oops.Oh(ErrorCode.E1002);
  127. var userId = user.Id;
  128. var loginOutput = user.Adapt<LoginOutput>();
  129. var httpContext = httpContextAccessor.HttpContext;
  130. loginOutput.LastLoginTime = user.LastLoginTime = DateTime.Now;
  131. loginOutput.LastLoginIp = user.LastLoginIp = httpContext.GetRequestIPv4();
  132. var client = Parser.GetDefault().Parse(httpContext.Request.Headers["User-Agent"]);
  133. loginOutput.LastLoginBrowser = client.UA.Family + client.UA.Major;
  134. loginOutput.LastLoginOs = client.OS.Family + client.OS.Major;
  135. // 角色信息
  136. loginOutput.SysRoles = await roleUserService.GetLoginUserRoleList(userId);
  137. // 权限信息
  138. loginOutput.Permissions = await menuService.GetLoginPermissionList(userId);
  139. // 系统所有权限信息
  140. loginOutput.AllPermissions = await menuService.GetAllPermissionList();
  141. // 菜单信息
  142. loginOutput.Menus = await menuService.GetLoginAntMenus(userId);
  143. // 更新用户最后登录Ip和时间
  144. await userRep.UpdateIncludeAsync(user, new[] { nameof(SysUser.LastLoginIp), nameof(SysUser.LastLoginTime) });
  145. // 增加登录日志
  146. await eventPublisher.PublishAsync(new ChannelEventSource("Create:VisLog",
  147. new SysLogVis
  148. {
  149. Name = loginOutput.Name,
  150. Success = true,
  151. Message = "登录成功",
  152. Ip = loginOutput.LastLoginIp,
  153. Browser = loginOutput.LastLoginBrowser,
  154. Os = loginOutput.LastLoginOs,
  155. VisType = LoginType.LOGIN,
  156. VisTime = loginOutput.LastLoginTime,
  157. Account = loginOutput.Account
  158. }));
  159. return loginOutput;
  160. }
  161. /// <summary>
  162. /// 退出
  163. /// </summary>
  164. /// <returns></returns>
  165. public async Task Logout()
  166. {
  167. var ip = httpContextAccessor.HttpContext.GetRequestIPv4();
  168. httpContextAccessor.HttpContext.SignoutToSwagger();
  169. //_httpContextAccessor.HttpContext.Response.Headers["access-token"] = "invalid token";
  170. // 增加退出日志
  171. await eventPublisher.PublishAsync(new ChannelEventSource("Create:VisLog",
  172. new SysLogVis
  173. {
  174. Name = CurrentSysUserInfo.Name,
  175. Success = true,
  176. Message = "退出成功",
  177. VisType = LoginType.LOGOUT,
  178. VisTime = DateTime.Now,
  179. Account = CurrentSysUserInfo.Account,
  180. Ip = ip
  181. }));
  182. }
  183. /// <summary>
  184. /// 获取验证码
  185. /// </summary>
  186. /// <returns></returns>
  187. public Task<GeneralCaptchaOutput> GetCaptcha()
  188. {
  189. // 图片大小要与前端保持一致(坐标范围)
  190. return Task.FromResult(captchaService.CreateCaptchaImage());
  191. }
  192. /// <summary>
  193. /// 校验验证码
  194. /// </summary>
  195. /// <param name="input"></param>
  196. /// <returns></returns>
  197. public Task<GeneralCaptchaOutput> VerifyCaptcha(GeneralCaptchaInput input)
  198. {
  199. return Task.FromResult(captchaService.CheckCode(input));
  200. }
  201. /// <summary>
  202. /// 获取临时密码
  203. /// </summary>
  204. /// <param name="input"></param>
  205. /// <returns></returns>
  206. public List<string> GetTempPassword(List<string> input)
  207. {
  208. List<string> ret = [];
  209. foreach (string pwd in input)
  210. {
  211. //var npwd = AESEncryption.Encrypt(pwd, _authOptions.AesPassword);
  212. var npwd = PBKDF2Encryption.Encrypt(pwd);
  213. ret.Add(npwd);
  214. }
  215. return ret;
  216. }
  217. }