SysAuthService.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. using Furion.SpecificationDocument;
  2. using Lazy.Captcha.Core;
  3. using Microsoft.Extensions.Caching.Memory;
  4. namespace Admin.NET.Core.Service;
  5. /// <summary>
  6. /// 系统登录授权服务
  7. /// </summary>
  8. [ApiDescriptionSettings(Order = 200)]
  9. public class SysAuthService : IDynamicApiController, ITransient
  10. {
  11. private readonly SqlSugarRepository<SysUser> _sysUserRep;
  12. private readonly RefreshTokenOptions _refreshTokenOptions;
  13. private readonly IHttpContextAccessor _httpContextAccessor;
  14. private readonly IUserManager _userManager;
  15. private readonly IEventPublisher _eventPublisher;
  16. private readonly SysUserService _sysUserService;
  17. private readonly SysUserRoleService _sysUserRoleService;
  18. private readonly SysMenuService _sysMenuService;
  19. private readonly ISysOnlineUserService _sysOnlineUserService;
  20. private readonly IMemoryCache _cache;
  21. private readonly ICaptcha _captcha;
  22. public SysAuthService(SqlSugarRepository<SysUser> sysUserRep,
  23. IOptions<RefreshTokenOptions> refreshTokenOptions,
  24. IHttpContextAccessor httpContextAccessor,
  25. IUserManager userManager,
  26. IEventPublisher eventPublisher,
  27. SysUserService sysUserService,
  28. SysUserRoleService sysUserRoleService,
  29. SysMenuService sysMenuService,
  30. ISysOnlineUserService sysOnlineUserService,
  31. IMemoryCache cache,
  32. ICaptcha captcha)
  33. {
  34. _sysUserRep = sysUserRep;
  35. _httpContextAccessor = httpContextAccessor;
  36. _userManager = userManager;
  37. _refreshTokenOptions = refreshTokenOptions.Value;
  38. _eventPublisher = eventPublisher;
  39. _sysUserService = sysUserService;
  40. _sysUserRoleService = sysUserRoleService;
  41. _sysMenuService = sysMenuService;
  42. _sysOnlineUserService = sysOnlineUserService;
  43. _cache = cache;
  44. _captcha = captcha;
  45. }
  46. /// <summary>
  47. /// 登录系统
  48. /// </summary>
  49. /// <param name="input"></param>
  50. /// <remarks>用户名/密码:vben/123456</remarks>
  51. /// <returns></returns>
  52. [HttpPost("/login")]
  53. [AllowAnonymous]
  54. [SuppressMonitor]
  55. public async Task<LoginOutput> Login([Required] LoginInput input)
  56. {
  57. // 判断验证码
  58. if (!_captcha.Validate(input.CodeId.ToString(), input.Code))
  59. throw Oops.Oh(ErrorCodeEnum.D0009);
  60. var encryptPasswod = MD5Encryption.Encrypt(input.Password); // 加密密码
  61. // 判断用户名密码
  62. var user = await _sysUserRep.AsQueryable().Includes(u => u.SysOrg)
  63. .FirstAsync(u => u.UserName.Equals(input.UserName) && u.Password.Equals(encryptPasswod));
  64. _ = user ?? throw Oops.Oh(ErrorCodeEnum.D1000);
  65. // 验证账号是否被冻结
  66. if (user.Status == StatusEnum.Disable)
  67. throw Oops.Oh(ErrorCodeEnum.D1017);
  68. // 单用户登录(强制下线其他地方登录账号)
  69. await _sysOnlineUserService.SignleLogin(user.Id);
  70. // 生成Token令牌
  71. var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
  72. {
  73. {ClaimConst.UserId, user.Id},
  74. {ClaimConst.TenantId, user.TenantId},
  75. {ClaimConst.UserName, user.UserName},
  76. {ClaimConst.RealName, user.RealName},
  77. {ClaimConst.SuperAdmin, user.UserType},
  78. {ClaimConst.OrgId, user.OrgId},
  79. {ClaimConst.OrgName, user.SysOrg?.Name},
  80. {ClaimConst.OrgLevel, user.SysOrg?.Level},
  81. });
  82. // 生成刷新Token令牌
  83. var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, _refreshTokenOptions.ExpiredTime);
  84. // 设置响应报文头
  85. _httpContextAccessor.HttpContext.SetTokensOfResponseHeaders(accessToken, refreshToken);
  86. // Swagger Knife4UI-AfterScript登录脚本
  87. // ke.global.setAllHeader('Authorization', 'Bearer ' + ke.response.headers['access-token']);
  88. return new LoginOutput
  89. {
  90. UserId = user.Id,
  91. Token = accessToken,
  92. RefreshToken = refreshToken
  93. };
  94. }
  95. /// <summary>
  96. /// 获取用户信息
  97. /// </summary>
  98. /// <returns></returns>
  99. [HttpGet("/getUserInfo")]
  100. public async Task<LoginUserInfoOutput> GetUserInfo()
  101. {
  102. var user = _userManager.User;
  103. if (user == null)
  104. throw Oops.Oh(ErrorCodeEnum.D1011);
  105. // 角色信息
  106. var roles = await _sysUserRoleService.GetUserRoleList(user.Id);
  107. // 数据范围
  108. var dataScopes = await _sysUserService.GetUserOrgIdList();
  109. // 按钮权限
  110. var buttons = await _sysMenuService.GetPermCodeList();
  111. // 登录日志
  112. var client = Parser.GetDefault().Parse(_httpContextAccessor.HttpContext.Request.Headers["User-Agent"]);
  113. await _eventPublisher.PublishAsync("Add:VisLog", new SysLogVis
  114. {
  115. Success = YesNoEnum.Y,
  116. Message = "登录",
  117. Ip = _httpContextAccessor.HttpContext.GetRemoteIpAddressToIPv4(),
  118. Browser = client.UA.Family + client.UA.Major,
  119. Os = client.OS.Family + client.OS.Major,
  120. VisType = LoginTypeEnum.Login,
  121. UserName = user.UserName,
  122. RealName = user.RealName
  123. });
  124. return new LoginUserInfoOutput
  125. {
  126. UserId = user.Id,
  127. Username = user.UserName,
  128. RealName = user.RealName,
  129. Avatar = user.Avatar,
  130. Desc = user.Introduction,
  131. OrgId = user.OrgId,
  132. OrgName = user.SysOrg != null ? user.SysOrg.Name : "",
  133. OrgLevel = user.SysOrg != null ? user.SysOrg.Level : "",
  134. Roles = roles.Select(u => new LoginRole
  135. {
  136. RoleName = u.Name,
  137. Value = u.Code
  138. }).ToList(),
  139. Buttons = buttons
  140. };
  141. }
  142. /// <summary>
  143. /// 获取刷新Token
  144. /// </summary>
  145. /// <param name="accessToken"></param>
  146. /// <returns></returns>
  147. [HttpPost("/getRefreshToken")]
  148. public string RefreshToken([Required] string accessToken)
  149. {
  150. return JWTEncryption.GenerateRefreshToken(accessToken, _refreshTokenOptions.ExpiredTime);
  151. }
  152. /// <summary>
  153. /// 退出系统
  154. /// </summary>
  155. [HttpGet("/logout")]
  156. public async void Logout()
  157. {
  158. var user = _userManager.User;
  159. if (user == null)
  160. throw Oops.Oh(ErrorCodeEnum.D1011);
  161. // 设置响应报文头
  162. _httpContextAccessor.HttpContext.SetTokensOfResponseHeaders(null, null);
  163. // 退出日志
  164. await _eventPublisher.PublishAsync("Add:VisLog", new SysLogVis
  165. {
  166. Success = YesNoEnum.Y,
  167. Message = "退出",
  168. VisType = LoginTypeEnum.Logout,
  169. Ip = _httpContextAccessor.HttpContext.GetRemoteIpAddressToIPv4(),
  170. UserName = user.UserName,
  171. RealName = user.RealName
  172. });
  173. }
  174. /// <summary>
  175. /// 生成图片验证码
  176. /// </summary>
  177. /// <returns></returns>
  178. [HttpGet("/captcha")]
  179. [AllowAnonymous]
  180. [SuppressMonitor]
  181. public dynamic GetCaptcha()
  182. {
  183. var codeId = Yitter.IdGenerator.YitIdHelper.NextId();
  184. var captcha = _captcha.Generate(codeId.ToString());
  185. return new { Id = codeId, Img = captcha.Base64 };
  186. }
  187. /// <summary>
  188. /// Swagger登录检查
  189. /// </summary>
  190. /// <returns></returns>
  191. [HttpPost("/Swagger/CheckUrl"), NonUnify]
  192. [AllowAnonymous]
  193. public int SwaggerCheckUrl()
  194. {
  195. return _cache.Get<bool>(CacheConst.SwaggerLogin) ? 200 : 401;
  196. }
  197. /// <summary>
  198. /// Swagger登录
  199. /// </summary>
  200. /// <param name="auth"></param>
  201. /// <returns></returns>
  202. [HttpPost("/Swagger/SubmitUrl"), NonUnify]
  203. [AllowAnonymous]
  204. public int SwaggerSubmitUrl([FromForm] SpecificationAuth auth)
  205. {
  206. var userName = App.GetConfig<string>("SpecificationDocumentSettings:LoginInfo:UserName");
  207. var password = App.GetConfig<string>("SpecificationDocumentSettings:LoginInfo:Password");
  208. if (auth.UserName == userName && auth.Password == password)
  209. {
  210. _cache.Set<bool>(CacheConst.SwaggerLogin, true);
  211. return 200;
  212. }
  213. return 401;
  214. }
  215. }