SysAuthService.cs 9.2 KB

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