You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
538 lines
22 KiB
538 lines
22 KiB
using ATS.NonCustodial.Application.Base; |
|
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.Auth; |
|
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.Auth.Input; |
|
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.Auth.Output; |
|
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.User; |
|
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.LoginLog.Input; |
|
using ATS.NonCustodial.Domain.Entities.Admins; |
|
using ATS.NonCustodial.Domain.Entities.Business; |
|
using ATS.NonCustodial.Domain.Entities.Business.EarlyWarning; |
|
using ATS.NonCustodial.Domain.Shared.Enums; |
|
using ATS.NonCustodial.Domain.Shared.OrmRepositories.Basic.EfCore; |
|
using ATS.NonCustodial.DynamicApi; |
|
using ATS.NonCustodial.DynamicApi.Attributes; |
|
using ATS.NonCustodial.Shared.Captcha.Dto; |
|
using ATS.NonCustodial.Shared.Common.Attributes; |
|
using ATS.NonCustodial.Shared.Common.Auth; |
|
using ATS.NonCustodial.Shared.Common.Constants; |
|
using ATS.NonCustodial.Shared.Common.Dtos; |
|
using ATS.NonCustodial.Shared.Common.Enums; |
|
using ATS.NonCustodial.Shared.Common.UnifiedResults; |
|
using ATS.NonCustodial.Shared.Configurations.Options; |
|
using ATS.NonCustodial.Shared.Extensions; |
|
using ATS.NonCustodial.Shared.Helpers; |
|
using ATS.NonCustodial.Shared.Helpers.Core.Hash; |
|
using ATS.NonCustodial.Shared.Helpers.Http; |
|
using ATS.NonCustodial.Shared.Tools.Captcha; |
|
using Microsoft.AspNetCore.Authorization; |
|
using Microsoft.AspNetCore.Cors; |
|
using Microsoft.AspNetCore.Mvc; |
|
using Microsoft.AspNetCore.Mvc.ModelBinding; |
|
using Microsoft.EntityFrameworkCore; |
|
using Newtonsoft.Json; |
|
using NPOI.SS.Formula.Functions; |
|
using NPOI.Util; |
|
using StackExchange.Profiling; |
|
using System.Diagnostics; |
|
using System.Security.Claims; |
|
using static System.Runtime.InteropServices.JavaScript.JSType; |
|
|
|
namespace ATS.NonCustodial.Application.Impl.Admins |
|
{ |
|
/// <summary> |
|
/// 认证授权服务 |
|
/// </summary> |
|
/// Author:mxg |
|
/// CreatedTimed:2022-05-15 11:04 PM |
|
[DynamicApi(Area = "admin")] |
|
public class AuthService : AdminAppServiceBase, IAuthService, IDynamicApi |
|
{ |
|
#region Identity |
|
|
|
private readonly VarifyCodeConfiguration _adminUiOptions; |
|
private readonly IEfRepository<App_Unitcode?, long> _appUnitRepository; |
|
private readonly IEfRepository<AppPermission?, long> _appPermissionRepository; |
|
private readonly IEfRepository<AppUser?, long> _appUserRepository; |
|
private readonly IEfRepository<AppUserRole?, long> _appUserRoleRepository; |
|
private readonly IEfRepository<AppRolePermission?, long> _appRolePermissionRepository; |
|
private readonly IEfRepository<AppView?, long> _appViewRepository; |
|
|
|
private readonly IEfRepository<AppEarlyWarning?, long> _appEarlyWarningRepository; |
|
private readonly IEfRepository<AppEarlyWarningRule?, long> _appEarlyWarningRuleRepository; |
|
|
|
private readonly ICaptchaTool _captchaTool; |
|
private readonly IUserService _userService; |
|
private readonly JwtConfiguration _jwtConfiguration; |
|
|
|
public AuthService( |
|
VarifyCodeConfiguration adminUiOptions, |
|
IEfRepository<AppUser?, long> appUserRepository, |
|
IEfRepository<App_Unitcode?, long> appUnitRepository, |
|
IEfRepository<AppEarlyWarning?, long> appEarlyWarningRepository, |
|
IEfRepository<AppEarlyWarningRule?, long> appEarlyWarningRuleRepository, |
|
IEfRepository<AppPermission?, long> appPermissionRepository, |
|
IEfRepository<AppUserRole?, long> appUserRoleRepository, |
|
IEfRepository<AppRolePermission?, long> appRolePermissionRepository, |
|
IEfRepository<AppView?, long> appViewRepository, |
|
ICaptchaTool captchaTool, |
|
IUserService userService, |
|
JwtConfiguration jwtConfiguration |
|
) |
|
{ |
|
_appEarlyWarningRepository = appEarlyWarningRepository; |
|
_appEarlyWarningRuleRepository = appEarlyWarningRuleRepository; |
|
_adminUiOptions = adminUiOptions; |
|
_appUserRepository = appUserRepository; |
|
_appUnitRepository = appUnitRepository; |
|
_appPermissionRepository = appPermissionRepository; |
|
_captchaTool = captchaTool; |
|
_appUserRoleRepository = appUserRoleRepository; |
|
_appRolePermissionRepository = appRolePermissionRepository; |
|
_appViewRepository = appViewRepository; |
|
_userService = userService; |
|
_jwtConfiguration = jwtConfiguration; |
|
} |
|
|
|
#endregion Identity |
|
|
|
/// <summary> |
|
/// 查询密钥 |
|
/// </summary> |
|
/// <returns></returns> |
|
[HttpGet] |
|
[AllowAnonymous] |
|
[NoOperationLog] |
|
public async Task<IResultOutput> GetPasswordEncryptKeyAsync() |
|
{ |
|
//写入Redis |
|
var guid = Guid.NewGuid().ToString("N"); |
|
var key = string.Format(CacheKey.passWordEncryptKey, guid); |
|
var encyptKey = StringHelper.GenerateRandom(8); |
|
await Cache.SetAsync(key, encyptKey, TimeSpan.FromMinutes(5)); |
|
var data = new { key = guid, encyptKey }; |
|
|
|
return ResultOutput.Ok(data); |
|
} |
|
|
|
/// <summary> |
|
/// 查询单位树 |
|
/// </summary> |
|
/// <returns></returns> |
|
[HttpGet] |
|
[AllowAnonymous] |
|
[NoOperationLog] |
|
public async Task<IResultOutput> GetUnitTreeAsync() |
|
{ |
|
var rtnlist = new List<dynamic>();//五条件返回结果 |
|
//监管机构 |
|
var express = _appUnitRepository.AsQueryable(false, true).Where(q => q.Stat == 0); |
|
if (express.Count() == 0) return ResultOutput.Ok(rtnlist); |
|
//单位集合 |
|
var dwgllist = _appUnitRepository.AsQueryable(false, true).Where(q => q.Stat == 1).ToList(); |
|
foreach (var item in await express.Where(q => q.ParentUnitCode == null || q.ParentUnitCode == 0).ToArrayAsync()) |
|
{ |
|
rtnlist.Add(new |
|
{ |
|
Id = item.Id, |
|
ParentUnitCode = item.ParentUnitCode, |
|
UnitCode = item.UnitCode, |
|
NameEntity = item.NameEntity, |
|
dw = true, |
|
children = pidlist(express.Where(q => q.ParentUnitCode != null || q.ParentUnitCode != 0).ToList(), item.Id, dwgllist) |
|
}); |
|
} |
|
return ResultOutput.Ok(rtnlist); |
|
} |
|
|
|
[HttpGet] |
|
[AllowAnonymous] |
|
[NoOperationLog] |
|
public async Task<IResultOutput> GetEarlyWarningAsync(int noticeCount) |
|
{ |
|
var rtnlist = new List<dynamic>();//五条件返回结果 |
|
//监管机构 |
|
//var express = _appEarlyWarningRepository.ExecuteSqlRawAsync(""); |
|
//var express = _appEarlyWarningRuleRepository.AsQueryable(false, true).Where(q => q.Stat == 0); |
|
return ResultOutput.Ok(rtnlist); |
|
} |
|
|
|
public static List<dynamic> pidlist(List<App_Unitcode> list, long pid, List<App_Unitcode> dwgllist) |
|
{ |
|
var plist = new List<dynamic>(); |
|
var dwgllist1 = new List<App_Unitcode>(); |
|
//通过监管机构查询查询单位 |
|
if (dwgllist != null) |
|
dwgllist1 = dwgllist.Where(q => q.mechanismId == pid).ToList(); |
|
|
|
//监管机构查询下级 |
|
foreach (var item in list.Where(q => q.ParentUnitCode == pid).ToList()) |
|
{ |
|
plist.Add(new |
|
{ |
|
Id = item.Id, |
|
ParentUnitCode = item.ParentUnitCode, |
|
NameEntity = item.NameEntity, |
|
UnitCode = item.UnitCode, |
|
dw = item.Stat == 0 ? true : false, |
|
children = pidlist(list, item.Id, dwgllist) |
|
}); |
|
} |
|
//单位查找下级 |
|
if (dwgllist1 != null) |
|
{ |
|
foreach (var item in dwgllist1.Where(q => q.ParentUnitCode == 0 || q.ParentUnitCode == null).ToList()) |
|
{ |
|
plist.Add(new |
|
{ |
|
Id = item.Id, |
|
ParentUnitCode = item.ParentUnitCode, |
|
NameEntity = item.NameEntity, |
|
UnitCode = item.UnitCode, |
|
dw = false, |
|
children = pidlist(dwgllist.Where(q => q.ParentUnitCode != 0 || q.ParentUnitCode != null).ToList(), item.Id, null) |
|
}); |
|
} |
|
} |
|
|
|
return plist; |
|
} |
|
|
|
/// <summary> |
|
/// 查询用户信息 |
|
/// </summary> |
|
/// <returns></returns> |
|
[Login] |
|
public async Task<IResultOutput> GetUserInfoAsync() |
|
{ |
|
if (!(User?.Id > 0)) return ResultOutput.NotOk("未登录!"); |
|
|
|
var authUserInfoOutput = new AuthUserInfoOutput |
|
{ |
|
//用户信息 |
|
User = await _appUserRepository.FetchAsync(w => new AuthUserProfileDto() |
|
{ |
|
UserName = w.UserName, |
|
NickName = w.NickName, |
|
Avatar = w.Avatar |
|
}, w => w.Id == User.Id) |
|
}; |
|
|
|
//用户菜单 |
|
var ptEnums = new[] { PermissionTypeEnum.Group, PermissionTypeEnum.Menu }; |
|
authUserInfoOutput.Menus = GetPermissionInfo(0, ptEnums) |
|
.Select(w => new AuthUserMenuDto() |
|
{ |
|
ViewPath = w, |
|
}).ToList(); |
|
|
|
//用户权限点 |
|
authUserInfoOutput.Permissions = GetPermissionInfo(1, PermissionTypeEnum.Dot); |
|
|
|
return ResultOutput.Ok(authUserInfoOutput); |
|
} |
|
|
|
/// <summary> |
|
/// 账号密码登录 |
|
/// </summary> |
|
/// <param name="input"></param> |
|
/// <returns></returns> |
|
[HttpPost] |
|
[AllowAnonymous] |
|
[NoOperationLog] |
|
public async Task<IResultOutput> LoginAsync(AuthLoginInput input) |
|
{ |
|
var user = await _appUserRepository.FindAsync(a => a.UserName == input.UserName && a.DataStatus == DataStatusEnum.Normal && (a.ChatPersonType == ChatPersonTypeEnum.Admin || a.ChatPersonType == ChatPersonTypeEnum.Supervisor)); |
|
|
|
if (user == null) return ResultOutput.NotOk($"{input.UserName}:用户不存在!"); |
|
|
|
return await LoginCommon(user, input.Password); |
|
} |
|
|
|
/// <summary> |
|
/// 手机号登录 |
|
/// </summary> |
|
/// <param name="input"></param> |
|
/// <returns></returns> |
|
[HttpPost] |
|
[AllowAnonymous] |
|
[NoOperationLog] |
|
public async Task<IResultOutput> LoginWithPhoneAsync(AuthLoginWithPhoneInput input) |
|
{ |
|
var user = await _appUserRepository.FindAsync(a => a.UnitId.Equals(input.UnitId) && (a.UserName == input.UserName || a.Phone == input.UserName) && a.DataStatus == DataStatusEnum.Normal && (a.ChatPersonType == ChatPersonTypeEnum.Admin || a.ChatPersonType == ChatPersonTypeEnum.Supervisor)); |
|
|
|
if (user == null) return ResultOutput.NotOk($"用户不存在,或者无权限登录!"); |
|
user.CId = input.CId; |
|
return await LoginCommon(user, input.Password); |
|
} |
|
|
|
/// <summary> |
|
/// 注销/推出登录 |
|
/// </summary> |
|
/// <returns></returns> |
|
public async Task<IResultOutput> LoginOutAsync() |
|
{ |
|
await User.LoginOutAsync(); |
|
return ResultOutput.Ok(); |
|
} |
|
|
|
/// <summary> |
|
/// 刷新Token |
|
/// 以旧换新 |
|
/// </summary> |
|
/// <param name="token"></param> |
|
/// <returns></returns> |
|
[HttpGet] |
|
[AllowAnonymous] |
|
public async Task<IResultOutput> Refresh([BindRequired] string token) |
|
{ |
|
var userClaims = LazyGetRequiredService<IUserToken>().Decode(token); |
|
if (userClaims == null || userClaims.Length == 0) return ResultOutput.NotOk(); |
|
|
|
var refreshExpires = userClaims.FirstOrDefault(a => a.Type == ClaimAttributes.refreshExpires)?.Value; |
|
if (refreshExpires.IsNull()) return ResultOutput.NotOk(); |
|
|
|
if (refreshExpires.ToLong() <= DateTime.Now.ToTimestamp()) return ResultOutput.NotOk("登录信息已过期"); |
|
|
|
var userId = userClaims.FirstOrDefault(a => a.Type == ClaimAttributes.userId)?.Value; |
|
if (userId.IsNull()) return ResultOutput.NotOk("登录信息已失效"); |
|
|
|
ResultOutput<AuthLoginOutput?>? output = await LazyGetRequiredService<IUserService>().GetLoginUserAsync(userId.ToLong()); |
|
string newToken = await GetToken(output?.Data); |
|
|
|
return ResultOutput.Ok(new { token = newToken }); |
|
} |
|
|
|
/// <summary> |
|
/// 获取验证数据 |
|
/// </summary> |
|
/// <returns></returns> |
|
[HttpGet] |
|
[AllowAnonymous] |
|
[NoOperationLog] |
|
[EnableCors(AdminConstant.allowAnyPolicyName)] |
|
public async Task<IResultOutput> GetCaptcha() |
|
{ |
|
using (MiniProfiler.Current.Step("获取滑块验证")) |
|
{ |
|
var data = await _captchaTool.GetAsync(CacheKey.captchaKey); |
|
return ResultOutput.Ok(data); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// 检查验证数据 |
|
/// </summary> |
|
/// <returns></returns> |
|
[HttpGet] |
|
[AllowAnonymous] |
|
[NoOperationLog] |
|
[EnableCors(AdminConstant.allowAnyPolicyName)] |
|
public async Task<IResultOutput> CheckCaptcha([FromQuery] CaptchaInput input) |
|
{ |
|
input.CaptchaKey = CacheKey.captchaKey; |
|
var result = await _captchaTool.CheckAsync(input); |
|
return ResultOutput.Result(result); |
|
} |
|
|
|
/// <summary> |
|
/// 获取登录信息 |
|
/// </summary> |
|
/// <param name="id"></param> |
|
/// <returns></returns> |
|
/// <exception cref="NotImplementedException"></exception> |
|
public async Task<UserValidateDto> GetUserValidateInfoAsync(long id) |
|
{ |
|
return await _appUserRepository.FetchAsync(x => new UserValidateDto() |
|
{ |
|
Id = x.Id, |
|
UserName = x.UserName, |
|
//Status = x.Status, |
|
Name = x.Name, |
|
//RoleIds = x.RoleIds, |
|
ValidationVersion = InfraHelper.Hash.GetHashedString(HashTypeEnum.Md5, x.UserName + x.Password) |
|
}, x => x.Id == id); |
|
} |
|
|
|
/// <summary> |
|
/// 获取权限信息公共逻辑方法 |
|
/// </summary> |
|
/// <param name="ptEnums"></param> |
|
/// <param name="type">返回类型(0:ViewPath、1:PermissionCode)</param> |
|
/// <returns></returns> |
|
public async Task<List<PermissionItem>> GetPermissionItems(int type = 0, params PermissionTypeEnum[] ptEnums) |
|
{ |
|
var data = (from pr in _appPermissionRepository.Where(w => ptEnums.Contains(w.Type)) |
|
join rp in _appRolePermissionRepository.AsQueryable(false, true) on pr.Id equals rp.PermissionId |
|
join ur in _appUserRoleRepository.AsQueryable(false, true) on new { a = rp.RoleId, b = User.Id } equals new { a = ur.RoleId, b = ur.UserId } |
|
join v in _appViewRepository.AsQueryable(false, true) on pr.ViewId equals v.Id |
|
select new |
|
{ |
|
pr, |
|
rp, |
|
ur, |
|
v |
|
}).ToList(); |
|
|
|
List<PermissionItem> result = new(); |
|
if (type == 0) result = data.Select(w => new PermissionItem() |
|
{ |
|
Role = w.ur.RoleId.ToString(), |
|
Url = w.v.Path |
|
}).ToList(); |
|
else if (type == 1) data.Select(w => new PermissionItem() |
|
{ |
|
Role = w.pr.Code, |
|
Url = w.v.Path |
|
}).ToList(); |
|
|
|
return result; |
|
} |
|
|
|
/// <summary> |
|
/// 根据身份证号获取电话号码 |
|
/// </summary> |
|
/// <param name="phone"></param> |
|
/// <returns></returns> |
|
[HttpGet] |
|
[AllowAnonymous] |
|
public async Task<IResultOutput> GetPhoneByIDCard(string idCard) |
|
{ |
|
var user = await _appUserRepository.FindAsync(a => a.ChatPersonType == ChatPersonTypeEnum.SupervisedPerson && a.IdCard == idCard); |
|
return ResultOutput.Ok(user?.Phone); |
|
} |
|
|
|
#region Private |
|
|
|
/// <summary> |
|
/// 获得token |
|
/// </summary> |
|
/// <param name="user">用户信息</param> |
|
/// <returns></returns> |
|
[NonAction] |
|
public async Task<string> GetToken(AuthLoginOutput? user) |
|
{ |
|
if (user == null) return string.Empty; |
|
|
|
var roles = (await _userService.IsAdmin(user.Id)).Roles.Select(w => w.Id).ToList(); |
|
string limits = _appUnitRepository.AsQueryable(false, true).Where(a => a.Id == user.UnitId).Select(a => a.limits).FirstOrDefault(); |
|
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); |
|
var timeLogin = Convert.ToInt64(ts.TotalMilliseconds).ToString(); |
|
var token = LazyGetRequiredService<IUserToken>().Create(new[] |
|
{ |
|
new Claim(ClaimAttributes.userId, user.Id.ToString()), |
|
new Claim(ClaimAttributes.userName, user.UserName!), |
|
new Claim(ClaimAttributes.userUnitId, user.UnitId.ToString()), |
|
new Claim(ClaimAttributes.userDeptcodeId, user.DeptcodeId.ToString()), |
|
new Claim(ClaimAttributes.userNickName, user?.NickName??"") , |
|
new Claim(ClaimAttributes.avatar,user?.Avatar??"") , |
|
new Claim(ClaimAttributes.roles,JsonConvert.SerializeObject(roles)), |
|
new Claim(ClaimAttributes.orgs,JsonConvert.SerializeObject(Array.Empty<long>())) , |
|
new Claim(ClaimAttributes.phone,user?.Phone??""), |
|
new Claim(ClaimAttributes.logtime,timeLogin), |
|
new Claim(ClaimAttributes.limits,limits), |
|
new Claim(ClaimAttributes.IsAdmin,user.IsAdmin?"true":"false"), |
|
new Claim(ClaimAttributes.personType,user?.ChatPersonType.ToString()!) |
|
}); |
|
|
|
return token; |
|
} |
|
|
|
/// <summary> |
|
/// 获取权限信息公共逻辑方法 |
|
/// </summary> |
|
/// <param name="ptEnums"></param> |
|
/// <param name="type">返回类型(0:ViewPath、1:PermissionCode)</param> |
|
/// <returns></returns> |
|
private List<string> GetPermissionInfo(int type = 0, params PermissionTypeEnum[] ptEnums) |
|
{ |
|
var data = (from pr in _appPermissionRepository.Where(w => ptEnums.Contains(w.Type)) |
|
join rp in _appRolePermissionRepository.AsQueryable(false, true) on pr.Id equals rp.PermissionId |
|
join ur in _appUserRoleRepository.AsQueryable(false, true) on new { a = rp.RoleId, b = User.Id } equals new { a = ur.RoleId, b = ur.UserId } |
|
join v in _appViewRepository.AsQueryable(false, true) on pr.ViewId equals v.Id |
|
select new |
|
{ |
|
pr, |
|
rp, |
|
ur, |
|
v |
|
}).ToList(); |
|
|
|
List<string> result = new(); |
|
if (type == 0) result = data.Select(w => w.v.Path).ToList(); |
|
else if (type == 1) result = data.Select(w => w.pr.Code).ToList(); |
|
|
|
return result; |
|
} |
|
|
|
/// <summary> |
|
/// 登录公共逻辑方法(一个设备只能登录一次) |
|
/// </summary> |
|
/// <param name="user"></param> |
|
/// <param name="password"></param> |
|
/// <returns></returns> |
|
/// <remarks> |
|
/// mac地址 + cookie |
|
/// 移动就就设备id |
|
/// PC端账号token做踢线处理 ,只能登陆一次,如果其他地方登陆了 更换token |
|
/// </remarks> |
|
private async Task<IResultOutput> LoginCommon(AppUser user, string password) |
|
{ |
|
//var userLoginKey = string.Format(CacheKey.AdminUserLogin, user.Id,); |
|
|
|
//var redisToken = await Cache.GetAsync(userLoginKey) ?? ""; |
|
|
|
//if (redisToken != User.GetToken()) ResultOutput.NotOk("同一个设备只能登录一次"); |
|
//if (!redisToken.IsNull()) return ResultOutput.Ok(new { redisToken }); |
|
|
|
//pc端和监管人员手机端只能登录监管人和admin,不能让被监管人登录 |
|
var isAdmin = await _userService.IsAdmin(user.Id); |
|
if (!isAdmin.IsAdmin && !isAdmin.Roles.Any(w => w.Code is "supervisor" or "admin")) return ResultOutput.NotOk($"被监管人员{user.UserName}:无权限登录!"); |
|
|
|
var sw = new Stopwatch(); |
|
sw.Start(); |
|
|
|
if (InfraHelper.Hash.GetHashedString(HashTypeEnum.Md5, password) != user.Password) return ResultOutput.NotOk("密码输入有误!"); |
|
//更新手机唯一标识码 |
|
if (!string.IsNullOrEmpty(user.CId)) |
|
{ |
|
//var userda = _userService.GetLoginUserAsync(user.Id); |
|
await _appUserRepository.UpdateAsync(user); |
|
} |
|
var authLoginOutput = Mapper.Map<AuthLoginOutput>(user); |
|
authLoginOutput.IsAdmin = isAdmin.IsAdmin; |
|
|
|
var token = await GetToken(authLoginOutput); |
|
|
|
sw.Stop(); |
|
|
|
//channel |
|
var channelWriter = ChannelHelper<LoginLogAddInput>.Instance.Writer; |
|
{ |
|
//添加登录日志 |
|
var httpContext = HttpContextHelper.GetCurrentHttpContext(); |
|
var loginLogAddInput = new LoginLogAddInput |
|
{ |
|
CreatedUserName = user.Name, |
|
ElapsedMilliseconds = sw.ElapsedMilliseconds, |
|
Status = true, |
|
CreatedUserId = authLoginOutput.Id, |
|
NickName = authLoginOutput.NickName, |
|
TenantId = authLoginOutput.TenantId, |
|
Device = httpContext?.Request.Headers["device"].FirstOrDefault() ?? "web", |
|
IP = httpContext?.Connection?.RemoteIpAddress?.MapToIPv4().ToString() |
|
}; |
|
|
|
await channelWriter.WriteAsync(loginLogAddInput); |
|
|
|
//await LazyGetRequiredService<ILoginLogService>().AddAsync(loginLogAddInput); |
|
} |
|
|
|
//将token写入Redis |
|
//await Cache.SetAsync(userLoginKey, token, TimeSpan.FromMinutes(_jwtConfiguration.Expires)); |
|
|
|
return ResultOutput.Ok(new { token }); |
|
} |
|
|
|
#endregion Private |
|
} |
|
} |