irc-netcore-api/IRaCIS.Core.Application/Service/Management/UserService.cs

918 lines
36 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using IP2Region.Net.Abstractions;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Helper.OtherTool;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using Medallion.Threading;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Panda.DynamicWebApi.Attributes;
using System.Text.RegularExpressions;
using ZiggyCreatures.Caching.Fusion;
using LoginReturnDTO = IRaCIS.Application.Contracts.LoginReturnDTO;
namespace IRaCIS.Core.Application.Service
{
[ApiExplorerSettings(GroupName = "Management")]
public class UserService(IRepository<User> _userRepository,
IMailVerificationService _mailVerificationService,
IRepository<VerificationCode> _verificationCodeRepository,
IRepository<TrialUser> _userTrialRepository,
IRepository<UserLog> _userLogRepository,
IRepository<UserPassWordLog> _userPassWordLogRepository,
IDistributedLockProvider _distributedLockProvider,
IRepository<Trial> _trialRepository,
IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig,
IOptionsMonitor<SystemHospitalOption> _systemHospitalConfig,
ISearcher _searcher, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, IUserService
{
private SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
private async Task VerifyUserNameAsync(Guid? userId, string userName)
{
if (await _userRepository.WhereIf(userId != null, t => t.Id != userId).AnyAsync(t => t.UserName == userName))
{
//---用户名已经存在。
throw new BusinessValidationFailedException(_localizer["User_UsernameExist"]);
}
}
private async Task VerifyUserPhoneAsync(Guid? userId, Guid userTypeId, string phone)
{
if (await _userRepository.WhereIf(userId != null, t => t.Id != userId).AnyAsync(t => (t.Phone == phone && t.UserTypeId == userTypeId)))
{
//---该用户类型中已存在具有相同的电话的用户。
throw new BusinessValidationFailedException(_localizer["User_PhoneDup"]);
}
}
private async Task VerifyUserEmailAsync(Guid? userId, Guid userTypeId, string email)
{
if (await _userRepository.WhereIf(userId != null, t => t.Id != userId).AnyAsync(t => (t.EMail == email && t.UserTypeId == userTypeId)))
{
//---该用户类型中已存在具有相同邮箱的用户。
throw new BusinessValidationFailedException(_localizer["User_EmailDup"]);
}
}
private async Task VerifyUserPwdAsync(Guid userId, string newPwd, string? oldPwd = null)
{
//var dbUser = (await _userRepository.FirstOrDefaultAsync(t => t.Id == userId)).IfNullThrowException();
if (_verifyConfig.CurrentValue.OpenUserComplexPassword)
{
if (oldPwd != null && oldPwd == newPwd)
{
//---新密码与旧密码相同。
throw new BusinessValidationFailedException(_localizer["User_NewOldPwdSame"]);
}
var dbUser = (await _userRepository.Where(t => t.Id == userId).FirstOrDefaultAsync()).IfNullThrowException();
if (oldPwd != null && dbUser.Password != oldPwd)
{
//---旧密码验证失败。
throw new BusinessValidationFailedException(_localizer["User_OldPwdInvalid"]);
}
if (dbUser.Password == newPwd)
{
//---新密码与旧密码相同。
throw new BusinessValidationFailedException(_localizer["User_NewOldPwdSame"]);
}
var passWordList = await _userPassWordLogRepository.Where(x => x.UserId == userId).OrderByDescending(x => x.CreateTime).Take(2).ToListAsync();
if (passWordList.Any(x => x.PassWord == newPwd))
{
throw new BusinessValidationFailedException(_localizer["User_PassWordRepeat"]);
}
}
if (oldPwd == null)
{
oldPwd = await _userRepository.Where(x => x.Id == userId).Select(x => x.Password).FirstOrDefaultAsync();
}
if (oldPwd.IsNotNullOrEmpty())
{
await _userPassWordLogRepository.AddAsync(new UserPassWordLog()
{
CreateTime = DateTime.Now,
PassWord = oldPwd!,
UserId = userId,
});
}
await _userRepository.BatchUpdateNoTrackingAsync(x => x.Id == userId, x => new User()
{
LastChangePassWordTime = DateTime.Now,
});
await _userPassWordLogRepository.SaveChangesAsync();
}
/// <summary>发送验证码 修改邮箱(已经登陆修改) New </summary>
[HttpGet("{email}")]
public async Task<IResponseOutput> SendVerificationCode(string email)
{
//检查手机或者邮箱是否有效
if (!Regex.IsMatch(email, @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"))
{
//---Please input a legal email
return ResponseOutput.NotOk(_localizer["User_LegalEmail"]);
}
//验证码 6位
int verificationCode = new Random().Next(100000, 1000000);
await _mailVerificationService.SendMailEditEmail(_userInfo.Id, _userInfo.RealName, email, verificationCode);
return ResponseOutput.Ok();
}
[HttpPut("{newEmail}/{verificationCode}")]
[UnitOfWork]
public async Task<IResponseOutput> SetNewEmail(string newEmail, string verificationCode)
{
var verificationRecord = await _verificationCodeRepository
.FirstOrDefaultAsync(t => t.UserId == _userInfo.Id && t.Code == verificationCode && t.CodeType == 0);
//检查数据库是否存在该验证码
if (verificationRecord == null)
{
//---验证码错误。
return ResponseOutput.NotOk(_localizer["User_VerificationCodeError"]);
}
else
{
//检查验证码是否失效
if (verificationRecord.ExpirationTime < DateTime.Now)
{
//---验证码已经过期。
return ResponseOutput.NotOk(_localizer["User_VerificationCodeExpired"]);
}
else if (verificationRecord.EmailOrPhone.Trim() != newEmail.Trim())
{
//发送验证嘛的和提交的邮箱不一致
return ResponseOutput.NotOk(_localizer["User_VerificationEmailNotSameWithBefore"]);
}
else //验证码正确 并且 没有超时
{
await VerifyUserEmailAsync(_userInfo.Id, _userInfo.UserTypeId, newEmail);
await _userRepository.UpdatePartialFromQueryAsync(_userInfo.Id, u => new User()
{
EMail = newEmail
});
//删除验证码历史记录
await _verificationCodeRepository.BatchDeleteNoTrackingAsync(t => t.UserId == _userInfo.Id && t.CodeType == 0);
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = _userInfo.Id, OptType = UserOptType.UpdateUser }, true);
return ResponseOutput.Ok();
}
}
}
[HttpPut("{newPhone}")]
public async Task<IResponseOutput> SetNewPhone(string newPhone)
{
await VerifyUserPhoneAsync(_userInfo.Id, _userInfo.UserTypeId, newPhone);
await _userRepository.UpdatePartialFromQueryAsync(_userInfo.Id, u => new User()
{
Phone = newPhone
});
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = _userInfo.Id, OptType = UserOptType.UpdateUser }, true);
return ResponseOutput.Ok();
}
[HttpPut("{newUserName}")]
public async Task<IResponseOutput> SetNewUserName(string newUserName)
{
await VerifyUserNameAsync(_userInfo.Id, newUserName);
await _userRepository.UpdatePartialFromQueryAsync(_userInfo.Id, u => new User()
{
UserName = newUserName
});
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = _userInfo.Id, OptType = UserOptType.UpdateUser }, true);
return ResponseOutput.Ok();
}
[HttpGet]
public async Task<IResponseOutput> InitSetUserNameAndPwd(Guid userId, string newUserName, string newPWd)
{
await VerifyUserPwdAsync(userId, newPWd);
await VerifyUserNameAsync(userId, newUserName);
await _userRepository.UpdatePartialFromQueryAsync(userId, u => new User()
{
UserName = newUserName,
Password = newPWd,
IsFirstAdd = false,
EmailToken = String.Empty
}, true);
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = _userInfo.Id, OptType = UserOptType.UpdateUser }, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 重置密码为 默认密码
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
[HttpGet("{userId:guid}")]
[UnitOfWork]
public async Task<IResponseOutput> ResetPassword(Guid userId)
{
//var pwd = IRCEmailPasswordHelper.GenerateRandomPassword(10);
var pwd = "123456";
if (_systemHospitalConfig.CurrentValue.IsCanConnectInternet)
{
await _mailVerificationService.AdminResetPwdSendEmailAsync(userId, pwd);
}
await _userRepository.UpdatePartialFromQueryAsync(userId, u => new User()
{
Password = MD5Helper.Md5(pwd),
IsFirstAdd = true
});
var userName = _userRepository.Where(t => t.Id == userId).Select(t => t.UserName).FirstOrDefault();
await _fusionCache.RemoveAsync(CacheKeys.UserLoginError(userName));
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = userId, OptType = UserOptType.ResetPassword }, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 重置密码发邮件 (未登陆修改)
/// </summary>
/// <param name="email"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpGet("{email}")]
public async Task<IResponseOutput> AnonymousSendVerificationCode(string email)
{
//检查手机或者邮箱是否有效
if (!Regex.IsMatch(email, @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"))
{
//---请输入一个正确的邮箱。
return ResponseOutput.NotOk(_localizer["User_InvalidEmail"]);
}
////查找改邮箱或者手机的用户
var exist = await _userRepository.AnyAsync(t => t.EMail == email);
if (!exist)
{
//---邮箱错误。
return ResponseOutput.NotOk(_localizer["User_EmailError"]);
}
//验证码 6位
int verificationCode = new Random().Next(100000, 1000000);
await _mailVerificationService.AnolymousSendEmailForResetAccount(email, verificationCode);
return ResponseOutput.Ok();
}
/// <summary>
/// (未登陆) 设置新密码
/// </summary>
/// <param name="userId"></param>
/// <param name="newPwd"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpGet("{userId:guid}/{newPwd}")]
public async Task<IResponseOutput> AnonymousSetPassword(Guid userId, string newPwd)
{
await VerifyUserPwdAsync(userId, newPwd);
var success = await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == userId, u => new User()
{
Password = newPwd,
IsFirstAdd = false
});
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = userId, OptUserId = userId, LoginPassword = newPwd, OptType = UserOptType.UnloginModifyPasswoed }, true);
return ResponseOutput.Result(success);
}
/// <summary>
/// 获取用户列表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<UserListDTO>> GetUserList(UserListQueryDTO inQuery)
{
var userQueryable = _userRepository.Where(x => x.UserTypeEnum != UserTypeEnum.SuperAdmin)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.UserName), t => t.UserName.Contains(inQuery.UserName))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.RealName), t => t.FullName.Contains(inQuery.RealName))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Phone), t => t.Phone.Contains(inQuery.Phone))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.OrganizationName), t => t.OrganizationName.Contains(inQuery.OrganizationName))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.EMail), t => t.EMail.Contains(inQuery.EMail))
.WhereIf(inQuery.BeginCreateTime != null, t => t.CreateTime >= inQuery.BeginCreateTime)
.WhereIf(inQuery.EndCreateTime != null, t => t.CreateTime <= inQuery.EndCreateTime)
.WhereIf(inQuery.BeginLastLoginTime != null, t => t.LastLoginTime >= inQuery.BeginLastLoginTime)
.WhereIf(inQuery.EndLastLoginTime != null, t => t.LastLoginTime <= inQuery.EndLastLoginTime)
.WhereIf(inQuery.UserType != null, t => t.UserTypeId == inQuery.UserType)
.WhereIf(inQuery.UserState != null, t => t.Status == inQuery.UserState)
.WhereIf(inQuery.IsTestUser != null, t => t.IsTestUser == inQuery.IsTestUser)
.WhereIf(inQuery.IsZhiZhun != null, t => t.IsZhiZhun == inQuery.IsZhiZhun)
.WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.OA, t => t.UserTypeEnum != UserTypeEnum.Admin)
.ProjectTo<UserListDTO>(_mapper.ConfigurationProvider);
return await userQueryable.ToPagedListAsync(inQuery);
}
/// <summary>
/// 根据用户Id获取用户详细信息[New]
/// </summary>
/// <param name="id"></param>
/// <returns></returns>xiuga
[HttpGet("{id:guid}")]
public async Task<UserDetailDTO> GetUser(Guid id)
{
var userQuery = _userRepository.Where(t => t.Id == id).ProjectTo<UserDetailDTO>(_mapper.ConfigurationProvider);
return await (userQuery.FirstOrDefaultAsync()).IfNullThrowException();
}
/// <summary>
/// 添加用户
/// </summary>
/// <param name="userAddModel"></param>
/// <returns></returns>
[UnitOfWork]
public async Task<IResponseOutput<UserAddedReturnDTO>> AddUser(UserCommand userAddModel)
{
await VerifyUserNameAsync(null, userAddModel.UserName);
await VerifyUserEmailAsync(null, userAddModel.UserTypeId, userAddModel.EMail);
//await VerifyUserPhoneAsync(null, userAddModel.UserTypeId, userAddModel.Phone);
var saveItem = _mapper.Map<User>(userAddModel);
var @lock = _distributedLockProvider.CreateLock($"UserAccount");
using (await @lock.AcquireAsync())
{
saveItem.Code = await _userRepository.Select(t => t.Code).DefaultIfEmpty().MaxAsync() + 1;
saveItem.UserCode = AppSettings.GetCodeStr(saveItem.Code, nameof(User));
//if (saveItem.IsZhiZhun)
//{
// var organizationName = _userInfo.IsEn_Us ? _systemEmailConfig.OrganizationName : _systemEmailConfig.OrganizationNameCN;
// saveItem.OrganizationName = organizationName;
//}
// IRCEmailPasswordHelper.GenerateRandomPassword(10)
saveItem.Password = MD5Helper.Md5("123456");
await _userRepository.AddAsync(saveItem);
var success = await _userRepository.SaveChangesAsync();
}
if (_systemHospitalConfig.CurrentValue.IsCanConnectInternet)
{
await _mailVerificationService.AddUserSendEmailAsync(saveItem.Id, userAddModel.BaseUrl, userAddModel.RouteUrl);
}
return ResponseOutput.Ok(new UserAddedReturnDTO { Id = saveItem.Id, UserCode = saveItem.UserCode });
}
/// <summary>
/// 更新用户
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public async Task<IResponseOutput> UpdateUser(UserCommand model)
{
await VerifyUserNameAsync(model.Id, model.UserName);
await VerifyUserEmailAsync(model.Id, model.UserTypeId, model.EMail);
//await VerifyUserPhoneAsync(model.Id, model.UserTypeId, model.Phone);
var user = await _userRepository.FirstOrDefaultAsync(t => t.Id == model.Id);
if (user == null) return Null404NotFound(user);
if (user.Status != model.Status)
{
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = model.Id, OptType = model.Status == UserStateEnum.Enable ? UserOptType.AccountEnable : UserOptType.AccountLocked }, true);
}
_mapper.Map(model, user);
//if (user.IsZhiZhun)
//{
// user.OrganizationName = _userInfo.IsEn_Us ? _systemEmailConfig.OrganizationName : _systemEmailConfig.OrganizationNameCN;
//}
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = model.Id, OptType = UserOptType.UpdateUser });
var success = await _userRepository.SaveChangesAsync();
return ResponseOutput.Ok(success);
}
/// <summary>
/// 删除用户
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
[HttpDelete("{userId:guid}")]
public async Task<IResponseOutput> DeleteUser(Guid userId)
{
if (await _userTrialRepository.AnyAsync(t => t.Id == userId))
{
//---该用户已经参加项目,不能够删除。
return ResponseOutput.NotOk(_localizer["User_InProject"]);
}
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = userId, OptType = UserOptType.DeleteUser }, true);
var success = await _userRepository.BatchDeleteNoTrackingAsync(t => t.Id == userId);
return ResponseOutput.Result(success);
}
/// <summary>
/// 禁用或者启用账户
/// </summary>
/// <param name="userId"></param>
/// <param name="state"></param>
/// <returns></returns>
[HttpPost("{userId:guid}/{state:int}")]
public async Task<IResponseOutput> UpdateUserState(Guid userId, UserStateEnum state)
{
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = userId, OptType = state == UserStateEnum.Enable ? UserOptType.AccountEnable : UserOptType.AccountLocked }, true);
var success = await _userRepository.BatchUpdateNoTrackingAsync(u => u.Id == userId, t => new User
{
Status = state
});
return ResponseOutput.Result(success);
}
public async Task<UserBasicInfo> GetUserBasicInfo(Guid userId, string pwd)
{
var info = await _userRepository.Where(u => u.Id == userId && u.Password == pwd).ProjectTo<UserBasicInfo>(_mapper.ConfigurationProvider).FirstNotNullAsync();
return info;
}
/// <summary>
/// 发送MFA 验证邮件
/// </summary>
/// <param name="userId"></param>
/// <param name="mfaType"></param>
/// <returns></returns>
[AllowAnonymous]
public async Task<IResponseOutput> SendMFAEmail(Guid userId, int mfaType)
{
var userInfo = await _userRepository.Where(u => u.Id == userId).Select(t => new { t.FullName, t.EMail }).FirstOrDefaultAsync();
int verificationCode = new Random().Next(100000, 1000000);
await _mailVerificationService.SenMFAVerifyEmail(userId, userInfo.FullName, userInfo.EMail, verificationCode, (UserMFAType)mfaType);
var hiddenEmail = IRCEmailPasswordHelper.MaskEmail(userInfo.EMail);
return ResponseOutput.Ok(hiddenEmail);
}
/// <summary>
/// 验证MFA 邮件
/// </summary>
/// <param name="userId"></param>
/// <param name="Code"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[AllowAnonymous]
public async Task<IResponseOutput> VerifyMFACodeAsync(Guid userId, string Code)
{
var verificationRecord = await _verificationCodeRepository.Where(t => t.UserId == userId && t.Code == Code && t.CodeType == VerifyType.Email).OrderByDescending(x => x.ExpirationTime).FirstOrDefaultAsync();
VerifyEmialGetDoctorInfoOutDto result = new VerifyEmialGetDoctorInfoOutDto();
//检查数据库是否存在该验证码
if (verificationRecord == null)
{
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = userId, OptUserId = userId, OptType = UserOptType.MFALoginFail }, true);
//---验证码错误。
throw new BusinessValidationFailedException(_localizer["TrialSiteSurvey_WrongVerificationCode"]);
}
else
{
//检查验证码是否失效
if (verificationRecord.ExpirationTime < DateTime.Now)
{
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = userId, OptUserId = userId, OptType = UserOptType.MFALoginFail }, true);
//---验证码已经过期。
throw new BusinessValidationFailedException(_localizer["TrialSiteSurvey_ExpiredVerificationCode"]);
}
else //验证码正确 并且 没有超时
{
//删除验证码历史记录
await _verificationCodeRepository.BatchDeleteNoTrackingAsync(t => t.Id == verificationRecord.Id);
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = userId, OptUserId = userId, OptType = UserOptType.MFALogin }, true);
}
}
return ResponseOutput.Ok();
}
//public async Task<IResponseOutput<LoginReturnDTO>> HospitalUserLogin(string token)
//{
// //同济医院token 地址http://192.168.40.88:8080
// //本地测试地址接口
// //RestClientAPI.PostAsync<>
//}
[NonDynamicMethod]
public async Task<IResponseOutput<LoginReturnDTO>> LoginSelectUserType(Guid userId, Guid userTypeId)
{
var userNamePwd = await _userRepository.Where(t => t.Id == userId && t.UserTypeId == userTypeId).Select(t => new { t.UserName, t.Password }).FirstNotNullAsync();
return await Login(userNamePwd.UserName, userNamePwd.Password);
}
/// <summary>
/// 用户登陆
/// </summary>
/// <param name="userName"></param>
/// <param name="password"></param>
/// <returns></returns>
[NonDynamicMethod]
public async Task<IResponseOutput<LoginReturnDTO>> Login(string userName, string password)
{
int maxFailures = _verifyConfig.CurrentValue.LoginMaxFailCount;
int lockoutMinutes = _verifyConfig.CurrentValue.LoginFailLockMinutes;
// 生成缓存键
string cacheKey = CacheKeys.UserLoginError(userName);
// 从缓存中获取登录失败次数
int? failCount = await _fusionCache.GetOrDefaultAsync<int?>(cacheKey);
if (failCount == null)
{
failCount = 0;
}
//每次登录 都重置缓存时间
await _fusionCache.SetAsync<int?>(cacheKey, failCount, TimeSpan.FromMinutes(lockoutMinutes));
if (failCount >= maxFailures)
{
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = Guid.Empty, OptUserId = Guid.Empty, LoginFaildName = userName, LoginPassword = password, OptType = UserOptType.AccountLocked }, true);
//$"密码连续错误{maxFailures}次,当前账号已被限制登录,请等待 {lockoutMinutes} 分钟后再试。"
throw new BusinessValidationFailedException(_localizer["User_ErrorLimit", maxFailures, lockoutMinutes]);
}
var userLoginReturnModel = new LoginReturnDTO();
var loginUser = await _userRepository.Where(u => u.UserName.Equals(userName) && u.Password == password).ProjectTo<UserBasicInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
if (loginUser == null)
{
//错误次数累加
failCount++;
await _fusionCache.SetAsync(cacheKey, failCount, TimeSpan.FromMinutes(lockoutMinutes));
var errorPwdUserId = await _userRepository.Where(u => u.UserName == userName).Select(t => t.Id).FirstOrDefaultAsync();
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = errorPwdUserId, OptUserId = errorPwdUserId, LoginFaildName = userName, LoginPassword = password, OptType = UserOptType.AccountOrPasswordError }, true);
return ResponseOutput.NotOk(_localizer["User_CheckNameOrPw"], new LoginReturnDTO());
}
if (loginUser.Status == 0)
{
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = loginUser.Id, OptUserId = loginUser.Id, LoginFaildName = userName, OptType = UserOptType.LoginLockedAccount }, true);
//---该用户已经被禁用。
return ResponseOutput.NotOk(_localizer["User_Disabled"], new LoginReturnDTO());
}
//登录成功 清除缓存
await _fusionCache.SetAsync(cacheKey, 0, TimeSpan.FromMinutes(lockoutMinutes));
var ipinfo = _searcher.Search(_userInfo.IP);
var iPRegion = string.Join('|', ipinfo.Split('|').TakeLast(3));
if (loginUser.LastLoginIP != string.Empty)
{
// 与上一次IP不一致
if (loginUser.LastLoginIP != iPRegion)
{
loginUser.LoginState = 2;
}
}
//超过90天没修改密码
if (_verifyConfig.CurrentValue.IsNeedChangePassWord && loginUser.LastChangePassWordTime != null && DateTime.Now.AddDays(-_verifyConfig.CurrentValue.ChangePassWordDays) > loginUser.LastChangePassWordTime.Value)
{
loginUser.LoginState = 1;
}
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = loginUser.Id, OptUserId = loginUser.Id, OptType = UserOptType.Login }, true);
userLoginReturnModel.BasicInfo = loginUser;
if (loginUser.LastChangePassWordTime == null)
{
await _userRepository.BatchUpdateNoTrackingAsync(x => x.Id == loginUser.Id, x => new User()
{
LastChangePassWordTime = DateTime.Now
});
}
await _userRepository.BatchUpdateNoTrackingAsync(x => x.Id == loginUser.Id, x => new User()
{
LastLoginIP = iPRegion,
LastLoginTime = DateTime.Now
});
userLoginReturnModel.AccountList = _userRepository.Where(t => t.EMail == userLoginReturnModel.BasicInfo.EMail && t.UserTypeEnum != UserTypeEnum.SuperAdmin)
.ProjectTo<UserAccountInfo>(_mapper.ConfigurationProvider).ToList();
return ResponseOutput.Ok(userLoginReturnModel);
}
[HttpPost]
public async Task<PageOutput<UserLogView>> GetUserLogList(UserLogQuery inQuery)
{
DateTime? trialCreateTime = inQuery.TrialId != null ? _trialRepository.Where(t => t.Id == inQuery.TrialId).Select(t => t.CreateTime).FirstOrDefault() : null;
var userLogQueryable =
_userLogRepository.AsQueryable().IgnoreQueryFilters()
.WhereIf(inQuery.TrialId != null, t => t.LoginUser.UserTrials.Any(c => c.TrialId == inQuery.TrialId && (c.UserId == t.LoginUserId || c.UserId == t.OptUserId)))
.WhereIf(trialCreateTime != null, t => t.CreateTime >= trialCreateTime)
.WhereIf(inQuery.OptType != null, t => t.OptType == inQuery.OptType)
.WhereIf(inQuery.UserId != null, t => t.LoginUserId == inQuery.UserId)
.WhereIf(inQuery.BeginDate != null, t => t.CreateTime >= inQuery.BeginDate)
.WhereIf(inQuery.EndDate != null, t => t.CreateTime <= inQuery.EndDate)
.WhereIf(!string.IsNullOrEmpty(inQuery.LoginUserName), t => t.LoginUser.UserName.Contains(inQuery.LoginUserName!))
.WhereIf(!string.IsNullOrEmpty(inQuery.LoginFaildName), t => t.LoginFaildName.Contains(inQuery.LoginFaildName!))
.WhereIf(!string.IsNullOrEmpty(inQuery.IP), t => t.IP.Contains(inQuery.IP!))
.WhereIf(inQuery.LoginUserTypeEnum != null, t => t.LoginUser.UserTypeEnum == inQuery.LoginUserTypeEnum)
.WhereIf(inQuery.UserTypeId != null, t => t.LoginUser.UserTypeId == inQuery.UserTypeId)
.ProjectTo<UserLogView>(_mapper.ConfigurationProvider);
var pageList = await userLogQueryable.ToPagedListAsync(inQuery);
return pageList;
}
[AllowAnonymous]
[HttpGet]
public async Task<IResponseOutput> LoginOut(Guid userId)
{
await _fusionCache.RemoveAsync(CacheKeys.UserToken(_userInfo.Id));
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = userId, OptUserId = _userInfo.Id, OptType = UserOptType.LoginOut }, true);
return ResponseOutput.Ok();
}
#region HIR 修改
/// <summary>
/// 验证验证码,没问题就返回用户所有的账户
/// </summary>
/// <param name="email"></param>
/// <param name="verifyCode"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[AllowAnonymous]
[HttpGet("{email}/{verifyCode}")]
public async Task<List<UserAccountDto>> VerifyAnonymousVerifyCode(string email, string verifyCode)
{
if (_systemHospitalConfig.CurrentValue.IsCanConnectInternet)
{
var verificationRecord = await _verificationCodeRepository
.Where(t => t.UserId == Guid.Empty && t.Code == verifyCode && t.CodeType == VerifyType.Email && t.EmailOrPhone == email).OrderByDescending(t => t.CreateTime).FirstOrDefaultAsync();
//检查数据库是否存在该验证码
if (verificationRecord == null)
{
//---验证码错误。
throw new BusinessValidationFailedException(_localizer["User_VerificationCodeError"]);
}
else
{
//检查验证码是否失效
if (verificationRecord.ExpirationTime < DateTime.Now)
{
//---验证码已经过期。
throw new BusinessValidationFailedException(_localizer["User_VerificationCodeExpired"]);
}
else //验证码正确 并且 没有超时
{
//删除验证码历史记录
await _verificationCodeRepository.BatchDeleteNoTrackingAsync(t => t.Id == verificationRecord.Id);
}
}
}
else
{
var isPass = _userRepository.Where(t => t.EMail == email).Any(t => t.CheckCode == verifyCode);
if (!isPass)
{
throw new BusinessValidationFailedException(_localizer["User_VerificationCodeError"]);
}
}
var list = await _userRepository.Where(t => t.EMail == email).Select(t => new UserAccountDto() { UserId = t.Id, UserName = t.UserName, UserRealName = t.FullName, UserType = t.UserTypeRole.UserTypeShortName }).ToListAsync();
return list;
}
[HttpPut("{newCheckCode}")]
public async Task<IResponseOutput> SetNewCheckCode(string newCheckCode)
{
var user = await _userRepository.FirstOrDefaultNoTrackingAsync(t => t.Id == _userInfo.Id);
await _userRepository.UpdatePartialFromQueryAsync(t => t.EMail == user.EMail, u => new User()
{
CheckCode = newCheckCode
});
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = _userInfo.Id, OptType = UserOptType.ModifyCheckCode }, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 修改密码,当前支持旧密码修改密码
/// </summary>
/// <returns></returns>
[HttpPost]
[UnitOfWork]
public async Task<IResponseOutput> ModifyPassword(EditPasswordCommand editPwModel)
{
await VerifyUserPwdAsync(_userInfo.Id, editPwModel.NewPassWord, editPwModel.OldPassWord);
if (!string.IsNullOrEmpty(editPwModel.NewUserName))
{
await VerifyUserNameAsync(_userInfo.Id, editPwModel.NewUserName);
await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == _userInfo.Id, u => new User()
{
UserName = editPwModel.NewUserName,
});
}
var success = await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == _userInfo.Id, u => new User()
{
Password = editPwModel.NewPassWord,
CheckCode = editPwModel.CheckCode,
IsFirstAdd = false
});
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.Id, OptUserId = _userInfo.Id, OptType = UserOptType.LoginModifyPassword }, true);
return ResponseOutput.Result(success);
}
#endregion
}
}