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

1152 lines
47 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 DocumentFormat.OpenXml.Wordprocessing;
using IP2Region.Net.Abstractions;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Auth;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using MassTransit;
using Medallion.Threading;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Org.BouncyCastle.Utilities.Encoders;
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<UserRole> _userRoleRepository,
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,
IRepository<IdentityUser> _identityUserRepository,
ISearcher _searcher, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, IUserService
{
private SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
private async Task VerifyUserNameAsync(Guid? identityUserId, string userName)
{
if (await _identityUserRepository.WhereIf(identityUserId != null, t => t.Id != identityUserId).AnyAsync(t => t.UserName == userName))
{
//---用户名已经存在。
throw new BusinessValidationFailedException(_localizer["User_UsernameExist"]);
}
}
private async Task VerifyUserPhoneAsync(Guid? identityUserId, string phone)
{
if (await _identityUserRepository.WhereIf(identityUserId != null, t => t.Id != identityUserId).AnyAsync(t => (t.Phone == phone)))
{
//---该用户类型中已存在具有相同的电话的用户。
throw new BusinessValidationFailedException(_localizer["User_PhoneDup"]);
}
}
private async Task VerifyUserEmailAsync(Guid? identityUserId, string email)
{
if (await _identityUserRepository.WhereIf(identityUserId != null, t => t.Id != identityUserId).AnyAsync(t => t.EMail == email))
{
//---该用户类型中已存在具有相同邮箱的用户。
throw new BusinessValidationFailedException(_localizer["User_EmailDup"]);
}
}
private async Task VerifyUserPwdAsync(Guid identityUserId, string newPwd, string? oldPwd = null)
{
//var dbUser = (await _userRoleRepository.FirstOrDefaultAsync(t => t.Id == userId)).IfNullThrowException();
if (_verifyConfig.CurrentValue.OpenUserComplexPassword)
{
if (oldPwd != null && oldPwd == newPwd)
{
//---新密码与旧密码相同。
throw new BusinessValidationFailedException(_localizer["User_NewOldPwdSame"]);
}
var dbUser = (await _identityUserRepository.Where(t => t.Id == identityUserId).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.IdentityUserId == identityUserId).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 _identityUserRepository.Where(x => x.Id == identityUserId).Select(x => x.Password).FirstOrDefaultAsync();
}
if (oldPwd.IsNotNullOrEmpty())
{
await _userPassWordLogRepository.AddAsync(new UserPassWordLog()
{
CreateTime = DateTime.Now,
PassWord = oldPwd!,
IdentityUserId = identityUserId,
});
}
await _identityUserRepository.BatchUpdateNoTrackingAsync(x => x.Id == identityUserId, x => new IdentityUser()
{
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.IdentityUserId, _userInfo.FullName, 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.UserRoleId && 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.IdentityUserId, newEmail);
await _identityUserRepository.UpdatePartialFromQueryAsync(_userInfo.IdentityUserId, u => new IdentityUser()
{
EMail = newEmail
});
//删除验证码历史记录
await _verificationCodeRepository.BatchDeleteNoTrackingAsync(t => t.UserId == _userInfo.UserRoleId && t.CodeType == 0);
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.UserRoleId, OptUserId = _userInfo.UserRoleId, OptType = UserOptType.UpdateUser }, true);
return ResponseOutput.Ok();
}
}
}
[HttpPut("{newPhone}")]
public async Task<IResponseOutput> SetNewPhone(string newPhone)
{
await VerifyUserPhoneAsync(_userInfo.IdentityUserId, newPhone);
await _identityUserRepository.UpdatePartialFromQueryAsync(_userInfo.IdentityUserId, u => new IdentityUser()
{
Phone = newPhone
});
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.UserRoleId, OptUserId = _userInfo.UserRoleId, OptType = UserOptType.UpdateUser }, true);
return ResponseOutput.Ok();
}
[HttpPut("{newUserName}")]
public async Task<IResponseOutput> SetNewUserName(string newUserName)
{
await VerifyUserNameAsync(_userInfo.IdentityUserId, newUserName);
await _identityUserRepository.UpdatePartialFromQueryAsync(_userInfo.IdentityUserId, u => new IdentityUser()
{
UserName = newUserName
});
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.UserRoleId, OptUserId = _userInfo.UserRoleId, OptType = UserOptType.UpdateUser }, true);
return ResponseOutput.Ok();
}
[HttpGet]
public async Task<IResponseOutput> InitSetUserNameAndPwd(string newUserName, string newPWd)
{
await VerifyUserPwdAsync(_userInfo.IdentityUserId, newPWd);
await VerifyUserNameAsync(_userInfo.IdentityUserId, newUserName);
await _identityUserRepository.UpdatePartialFromQueryAsync(_userInfo.IdentityUserId, u => new IdentityUser()
{
UserName = newUserName,
Password = newPWd,
IsFirstAdd = false,
EmailToken = String.Empty
}, true);
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.UserRoleId, OptUserId = _userInfo.UserRoleId, OptType = UserOptType.UpdateUser }, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 重置密码为 默认密码
/// </summary>
/// <param name="identityUserId"></param>
/// <returns></returns>
[HttpGet("{identityUserId:guid}")]
[UnitOfWork]
public async Task<IResponseOutput> ResetPassword(Guid identityUserId)
{
var pwd = IRCEmailPasswordHelper.GenerateRandomPassword(10);
await _mailVerificationService.AdminResetPwdSendEmailAsync(identityUserId, pwd);
await _identityUserRepository.UpdatePartialFromQueryAsync(t => t.Id == identityUserId, u => new IdentityUser()
{
Password = MD5Helper.Md5(pwd),
IsFirstAdd = true
});
var userName = _identityUserRepository.Where(t => t.Id == identityUserId).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 _identityUserRepository.AnyAsync(t => t.EMail == email && t.Status == UserStateEnum.Enable);
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="email"></param>
/// <param name="verifyCode"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[AllowAnonymous]
[HttpGet("{email}/{verifyCode}")]
public async Task<UserAccountDto> VerifyAnonymousVerifyCode(string email, string verifyCode)
{
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);
}
}
var userInfo = await _identityUserRepository.Where(t => t.EMail == email && t.Status == UserStateEnum.Enable).Select(t => new UserAccountDto() { Id = t.Id, UserName = t.UserName, UserRealName = t.FullName }).FirstOrDefaultAsync();
return userInfo;
}
/// <summary>
/// (未登陆) 设置新密码
/// </summary>
/// <param name="identityUserId"></param>
/// <param name="newPwd"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpGet("{identityUserId:guid}/{newPwd}")]
public async Task<IResponseOutput> AnonymousSetPassword(Guid identityUserId, string newPwd)
{
await VerifyUserPwdAsync(identityUserId, newPwd);
var success = await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == identityUserId, u => new IdentityUser()
{
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>
/// <returns></returns>
[HttpPost]
[UnitOfWork]
public async Task<IResponseOutput> ModifyPassword(EditPasswordCommand editPwModel)
{
await VerifyUserPwdAsync(_userInfo.IdentityUserId, editPwModel.NewPassWord, editPwModel.OldPassWord);
if (!string.IsNullOrEmpty(editPwModel.NewUserName))
{
await VerifyUserNameAsync(_userInfo.UserRoleId, editPwModel.NewUserName);
await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == _userInfo.IdentityUserId, u => new IdentityUser()
{
UserName = editPwModel.NewUserName,
});
}
var success = await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == _userInfo.IdentityUserId, u => new IdentityUser()
{
Password = editPwModel.NewPassWord,
IsFirstAdd = false
});
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = _userInfo.UserRoleId, OptUserId = _userInfo.UserRoleId, OptType = UserOptType.LoginModifyPassword }, true);
return ResponseOutput.Result(success);
}
/// <summary>
/// 获取用户列表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<UserListDTO>> GetUserList(UserListQueryDTO inQuery)
{
var userQueryable = _identityUserRepository.Where(x => x.UserRoleList.Any(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.UserRoleList.Any(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)
.ProjectTo<UserListDTO>(_mapper.ConfigurationProvider);
//var userQueryable = _identityUserRepository.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)
// .GroupBy(t => t.IdentityUserId).Select(g => new UserListDTO()
// {
// IdentityUserId = g.Key,
// UserRoleList = g.Select(c => new UserAddUserType()
// {
// UserTypeEnum = c.UserTypeEnum,
// UserTypeId = c.UserTypeId,
// }).ToList(),
// UserCode = g.FirstOrDefault().UserCode,
// DepartmentName = g.FirstOrDefault().DepartmentName,
// CreateTime = g.FirstOrDefault().CreateTime,
// EMail = g.FirstOrDefault().EMail,
// FirstName = g.FirstOrDefault().FirstName,
// IsTestUser = g.FirstOrDefault().IsTestUser,
// IsZhiZhun = g.FirstOrDefault().IsZhiZhun,
// LastName = g.FirstOrDefault().LastName,
// OrganizationName = g.FirstOrDefault().OrganizationName,
// FullName = g.FirstOrDefault().FullName,
// Phone = g.FirstOrDefault().Phone,
// PositionName = g.FirstOrDefault().PositionName,
// Sex = g.FirstOrDefault().Sex,
// Status = g.FirstOrDefault().Status,
// UserName = g.FirstOrDefault().UserName,
// });
return await userQueryable.ToPagedListAsync(inQuery);
}
/// <summary>
/// 根据用户Id获取用户详细信息[New]
/// </summary>
/// <returns></returns>xiuga
public async Task<UserDetailDTO> GetUser(Guid identityUserId)
{
identityUserId = identityUserId != Guid.Empty ? identityUserId : _userInfo.IdentityUserId;
var user = await _identityUserRepository.Where(t => t.Id == _userInfo.IdentityUserId).ProjectTo<UserDetailDTO>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
user.AccountList = await _userRoleRepository.Where(t => t.IdentityUserId == _userInfo.IdentityUserId).ProjectTo<UserAccountInfo>(_mapper.ConfigurationProvider).ToListAsync();
return user;
}
///// <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 _userRoleRepository.BatchDeleteNoTrackingAsync(t => t.Id == userId);
// return ResponseOutput.Result(success);
//}
/// <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.EMail);
//await VerifyUserPhoneAsync(null, userAddModel.UserTypeId, userAddModel.Phone);
var saveItem = _mapper.Map<IdentityUser>(userAddModel);
var @lock = _distributedLockProvider.CreateLock($"UserAccount");
using (await @lock.AcquireAsync())
{
saveItem.Code = await _identityUserRepository.Select(t => t.Code).DefaultIfEmpty().MaxAsync() + 1;
saveItem.UserCode = AppSettings.GetCodeStr(saveItem.Code, nameof(IdentityUser));
if (saveItem.IsZhiZhun)
{
var organizationName = _userInfo.IsEn_Us ? _systemEmailConfig.OrganizationName : _systemEmailConfig.OrganizationNameCN;
saveItem.OrganizationName = organizationName;
}
saveItem.Password = MD5Helper.Md5(IRCEmailPasswordHelper.GenerateRandomPassword(10));
var addRoleList = new List<UserRole>();
foreach (var role in userAddModel.UserRoleList)
{
var addRole = _mapper.Map<UserRole>(userAddModel);
addRole.UserTypeEnum = role.UserTypeEnum;
addRole.UserTypeId = role.UserTypeId;
addRoleList.Add(addRole);
}
saveItem.UserRoleList = addRoleList;
await _identityUserRepository.AddAsync(saveItem);
var success = await _identityUserRepository.SaveChangesAsync();
}
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.EMail);
//await VerifyUserPhoneAsync(model.Id, model.UserTypeId, model.Phone);
var user = await _identityUserRepository.Where(t => t.Id == model.Id, true).Include(t => t.UserRoleList).FirstOrDefaultAsync();
if (user == null) return Null404NotFound(user);
var existDBRoleList = user.UserRoleList;
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.UserRoleId, OptUserId = model.Id, OptType = UserOptType.UpdateUser });
//处理角色的添加、禁用
foreach (var role in model.UserRoleList)
{
var find = existDBRoleList.FirstOrDefault(t => t.UserTypeEnum == role.UserTypeEnum && t.UserTypeId == role.UserTypeId);
if (find != null)
{
find.IsUserRoleDisabled = false;
}
else
{
var addRole = _mapper.Map<UserRole>(model);
addRole.UserTypeEnum = role.UserTypeEnum;
addRole.UserTypeId = role.UserTypeId;
existDBRoleList.Add(addRole);
}
}
user.UserRoleList = existDBRoleList;
var success = await _userRoleRepository.SaveChangesAsync();
return ResponseOutput.Ok(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 _identityUserRepository.BatchUpdateNoTrackingAsync(u => u.IdentityUserId == userId, t => new User
// {
// Status = state
// });
// return ResponseOutput.Result(success);
//}
public async Task<UserBasicInfo> GetUserBasicInfo(Guid userId, string pwd)
{
var info = await _identityUserRepository.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, UserMFAType mfaType)
{
var userInfo = await _identityUserRepository.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();
}
/// <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 _userRoleRepository.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 _identityUserRepository.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.IdentityUserId, OptUserId = loginUser.IdentityUserId, 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.IdentityUserId, OptUserId = loginUser.IdentityUserId, OptType = UserOptType.Login }, true);
userLoginReturnModel.BasicInfo = loginUser;
if (loginUser.LastChangePassWordTime == null)
{
await _identityUserRepository.BatchUpdateNoTrackingAsync(x => x.Id == loginUser.IdentityUserId, x => new IdentityUser()
{
LastChangePassWordTime = DateTime.Now
});
}
await _identityUserRepository.BatchUpdateNoTrackingAsync(x => x.Id == loginUser.IdentityUserId, x => new IdentityUser()
{
LastLoginIP = iPRegion,
LastLoginTime = DateTime.Now
});
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 identityUserId)
{
await _fusionCache.RemoveAsync(CacheKeys.UserToken(identityUserId));
return ResponseOutput.Ok();
}
#region 多账号修改
/// <summary>
/// 账号验证,获取账号角色信息 获取临时token
/// </summary>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[AllowAnonymous]
[HttpPost]
public async Task<IResponseOutput<IRCLoginReturnDTO>> GetUserLoginRoleList(IRCLoginDto loginDto,
[FromServices] ITokenService _tokenService,
[FromServices] IOptionsMonitor<SystemEmailSendConfig> _emailConfig,
[FromServices] IReadingImageTaskService readingImageTaskService)
{
var userName = loginDto.UserName;
var password = loginDto.Password;
var emailConfig = _emailConfig.CurrentValue;
var companyInfo = new SystemEmailSendConfigView() { CompanyName = emailConfig.CompanyName, CompanyNameCN = emailConfig.CompanyNameCN, CompanyShortName = emailConfig.CompanyShortName, CompanyShortNameCN = emailConfig.CompanyShortNameCN };
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 IRCLoginReturnDTO();
var loginUser = await _identityUserRepository.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 _identityUserRepository.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 IRCLoginReturnDTO());
}
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 IRCLoginReturnDTO());
}
//登录成功 清除缓存
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 _identityUserRepository.BatchUpdateNoTrackingAsync(x => x.Id == loginUser.IdentityUserId, x => new IdentityUser()
{
LastChangePassWordTime = DateTime.Now
});
}
await _identityUserRepository.BatchUpdateNoTrackingAsync(x => x.Id == loginUser.IdentityUserId, x => new IdentityUser()
{
LastLoginIP = iPRegion,
LastLoginTime = DateTime.Now
});
//返回临时token
userLoginReturnModel.JWTStr = _tokenService.GetToken(new UserTokenInfo() { IdentityUserId = loginUser.IdentityUserId, UserName = userName });
var identityUserId = loginUser.IdentityUserId;
if (_verifyConfig.CurrentValue.OpenLoginMFA)
{
//MFA 发送邮件
userLoginReturnModel.IsMFA = true;
var email = userLoginReturnModel.BasicInfo.EMail;
var hiddenEmail = IRCEmailPasswordHelper.MaskEmail(email);
userLoginReturnModel.BasicInfo.EMail = hiddenEmail;
//修改密码
if (userLoginReturnModel.BasicInfo.IsFirstAdd || userLoginReturnModel.BasicInfo.LoginState == 1)
{
//userLoginReturnModel.JWTStr = _tokenService.GetToken(userLoginReturnModel.BasicInfo);
}
else
{
//正常登录才发送邮件
await SendMFAEmail(identityUserId, UserMFAType.Login);
}
}
else
{
// 验证阅片休息时间
await readingImageTaskService.ResetReadingRestTime(userLoginReturnModel.BasicInfo.IdentityUserId);
await _fusionCache.SetAsync(CacheKeys.UserToken(identityUserId), userLoginReturnModel.JWTStr, TimeSpan.FromDays(7));
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(identityUserId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(_verifyConfig.CurrentValue.AutoLoginOutMinutes));
}
userLoginReturnModel.BasicInfo.AccountList = await _userRoleRepository.Where(t => t.IdentityUserId == identityUserId).ProjectTo<UserAccountInfo>(_mapper.ConfigurationProvider).ToListAsync();
userLoginReturnModel.CompanyInfo = companyInfo;
return ResponseOutput.Ok(userLoginReturnModel);
}
/// <summary>
/// 验证密码成功后选定角色然后获取当前角色的Token
/// </summary>
/// <param name="userRoleId"></param>
/// <param name="_tokenService"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[HttpGet]
public async Task<string> LoginSelectUserRole(Guid userRoleId, [FromServices] ITokenService _tokenService)
{
var identityUserId = _userInfo.IdentityUserId;
var userTokenInfo = await _userRoleRepository.Where(t => t.IdentityUserId == identityUserId && t.Id == userRoleId).Select(t => new UserTokenInfo()
{
UserRoleId = t.Id,
IdentityUserId = t.IdentityUserId,
UserTypeEnum = t.UserTypeEnum,
UserTypeId = t.UserTypeId,
IsTestUser = t.IsTestUser,
IsZhiZhun = t.IsZhiZhun,
FullName = t.FullName,
PermissionStr = t.UserTypeRole.PermissionStr,
UserName = t.UserName,
UserTypeShortName = t.UserTypeRole.UserTypeShortName,
}).FirstOrDefaultAsync();
if (userTokenInfo != null)
{
var jwt = _tokenService.GetToken(userTokenInfo);
return jwt;
}
else
{
throw new BusinessValidationFailedException("传递参数查询数据库不存在!");
}
}
#endregion
}
}