From f55fa98deca370055beb041ec1362834ca727368 Mon Sep 17 00:00:00 2001
From: he <109787524@qq.com>
Date: Tue, 7 May 2024 14:45:32 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Service/Management/DTO/UserModel.cs | 11 +-
.../Service/Management/UserService.cs | 113 +++++++++++++-----
IRaCIS.Core.Domain/Management/User.cs | 9 +-
.../Management/UserPassWordLog.cs | 43 +++++++
.../Context/IRaCISDBContext.cs | 4 +-
.../_IRaCIS/Output/ApiResponseCodeEnum.cs | 14 ++-
.../_IRaCIS/Output/ResponseOutput.cs | 4 +-
IRaCIS.Core.Test/DbHelper.ttinclude | 4 +-
8 files changed, 157 insertions(+), 45 deletions(-)
create mode 100644 IRaCIS.Core.Domain/Management/UserPassWordLog.cs
diff --git a/IRaCIS.Core.Application/Service/Management/DTO/UserModel.cs b/IRaCIS.Core.Application/Service/Management/DTO/UserModel.cs
index 96c9037d2..5f65c4d00 100644
--- a/IRaCIS.Core.Application/Service/Management/DTO/UserModel.cs
+++ b/IRaCIS.Core.Application/Service/Management/DTO/UserModel.cs
@@ -39,8 +39,11 @@ namespace IRaCIS.Application.Contracts
public UserTypeEnum UserTypeEnum { get; set; }
-
- public bool IsTestUser { get; set; }
+ ///
+ /// 上一次修改密码的时间
+ ///
+ public DateTime? LastChangePassWordTime { get; set; }
+ public bool IsTestUser { get; set; }
public bool IsAdmin { get; set; } = false;
public string UserTypeShortName { get; set; } = string.Empty;
public bool PasswordChanged { get; set; }
@@ -55,7 +58,9 @@ namespace IRaCIS.Application.Contracts
public bool IsFirstAdd { get; set; }
public bool IsReviewer { get; set; } = false;
- }
+ public int LoginState { get; set; } = 0;
+
+ }
public class MenuFuncTreeNodeView
{
diff --git a/IRaCIS.Core.Application/Service/Management/UserService.cs b/IRaCIS.Core.Application/Service/Management/UserService.cs
index 945fd09ec..27f6734ea 100644
--- a/IRaCIS.Core.Application/Service/Management/UserService.cs
+++ b/IRaCIS.Core.Application/Service/Management/UserService.cs
@@ -23,13 +23,14 @@ namespace IRaCIS.Application.Services
public class UserService : BaseService, IUserService
{
private readonly IRepository _userRepository;
- private readonly IMailVerificationService _mailVerificationService;
+
+ private readonly IMailVerificationService _mailVerificationService;
private readonly IRepository _verificationCodeRepository;
private readonly IRepository _doctorRepository;
private readonly IRepository _userTrialRepository;
private readonly IRepository _userLogRepository;
-
- private readonly IDistributedLockProvider _distributedLockProvider;
+ private readonly IRepository _userPassWordLogRepository;
+ private readonly IDistributedLockProvider _distributedLockProvider;
private readonly IEasyCachingProvider _cache;
private readonly IReadingImageTaskService _readingImageTaskService;
private readonly IOptionsMonitor _verifyConfig;
@@ -44,13 +45,14 @@ namespace IRaCIS.Application.Services
IReadingImageTaskService readingImageTaskService,
IRepository userTrialRepository,
IOptionsMonitor verifyConfig,
- IRepository userLogRepository
+ IRepository userLogRepository,
+ IRepository userPassWordLogRepository
,
IDistributedLockProvider distributedLockProvider)
{
_userLogRepository = userLogRepository;
-
- _verifyConfig = verifyConfig;
+ this._userPassWordLogRepository = userPassWordLogRepository;
+ _verifyConfig = verifyConfig;
_cache = cache;
this._readingImageTaskService = readingImageTaskService;
_userRepository = userRepository;
@@ -94,36 +96,51 @@ namespace IRaCIS.Application.Services
private async Task VerifyUserPwdAsync(Guid userId, string newPwd, string? oldPwd = null)
{
- //var dbUser = (await _userRepository.FirstOrDefaultAsync(t => t.Id == userId)).IfNullThrowException();
+ //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"]);
+ }
+
+ await _userPassWordLogRepository.AddAsync(new UserPassWordLog()
{
- if (oldPwd != null && oldPwd == newPwd)
- {
- //---新密码与旧密码相同。
- throw new BusinessValidationFailedException(_localizer["User_NewOldPwdSame"]);
- }
+ CreateTime = DateTime.Now,
+ PassWord = oldPwd,
+ UserId = userId,
+ });
+
+ await _userRepository.BatchUpdateNoTrackingAsync(x => x.Id == userId, x => new User()
+ {
+ LastChangePassWordTime = DateTime.Now,
+ });
+ await _userPassWordLogRepository.SaveChangesAsync();
- 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"]);
- }
-
-
- }
-
- await Task.CompletedTask;
+ await Task.CompletedTask;
}
@@ -650,7 +667,7 @@ namespace IRaCIS.Application.Services
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);
+ 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]);
@@ -668,7 +685,7 @@ namespace IRaCIS.Application.Services
failCount++;
_cache.Set(cacheKey, failCount, TimeSpan.FromMinutes(lockoutMinutes));
- await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = Guid.Empty, OptUserId=Guid.Empty, LoginFaildName = userName, LoginPassword = password, OptType = UserOptType.AccountOrPasswordError }, true);
+ await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = Guid.Empty, OptUserId = Guid.Empty, LoginFaildName = userName, LoginPassword = password, OptType = UserOptType.AccountOrPasswordError }, true);
return ResponseOutput.NotOk(_localizer["User_CheckNameOrPw"], new LoginReturnDTO());
@@ -684,14 +701,44 @@ namespace IRaCIS.Application.Services
return ResponseOutput.NotOk(_localizer["User_Disabled"], new LoginReturnDTO());
}
+ //超过90天没修改密码
+ if (loginUser.LastChangePassWordTime != null && DateTime.Now.AddDays(-90) > loginUser.LastChangePassWordTime.Value)
+ {
+ loginUser.LoginState = 1;
+ }
+
+
//登录成功 清除缓存
_cache.Set(cacheKey, 0, TimeSpan.FromMinutes(lockoutMinutes));
+ var lastLoginLog = await _userLogRepository.Where(x => x.LoginUserId == loginUser.Id).OrderByDescending(x => x.CreateTime).FirstOrDefaultAsync();
+ if (lastLoginLog!=null)
+ {
+ if (lastLoginLog.IP != _userInfo.IP)
+ {
+ loginUser.LoginState = 2;
+ }
+
+
+ }
+
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
+
+ });
+
+ }
+
+
+
// 登录 清除缓存
//_cache.Remove(userLoginReturnModel.BasicInfo.Id.ToString());
diff --git a/IRaCIS.Core.Domain/Management/User.cs b/IRaCIS.Core.Domain/Management/User.cs
index 32ae20058..e47cbd423 100644
--- a/IRaCIS.Core.Domain/Management/User.cs
+++ b/IRaCIS.Core.Domain/Management/User.cs
@@ -78,8 +78,13 @@ namespace IRaCIS.Core.Domain.Models
public string EmailToken { get; set; } = string.Empty;
- //ҽ˺źֵ
- public Guid? DoctorId { get; set; }
+ ///
+ /// һʱ
+ ///
+ public DateTime? LastChangePassWordTime { get; set; }
+
+ //ҽ˺źֵ
+ public Guid? DoctorId { get; set; }
[JsonIgnore]
[ForeignKey("DoctorId")]
diff --git a/IRaCIS.Core.Domain/Management/UserPassWordLog.cs b/IRaCIS.Core.Domain/Management/UserPassWordLog.cs
new file mode 100644
index 000000000..63ceb7d7b
--- /dev/null
+++ b/IRaCIS.Core.Domain/Management/UserPassWordLog.cs
@@ -0,0 +1,43 @@
+
+//--------------------------------------------------------------------
+// 此代码由T4模板自动生成 byzhouhang 20210918
+// 生成时间 2024-05-07 13:47:08
+// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
+using System;
+using IRaCIS.Core.Domain.Share;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+namespace IRaCIS.Core.Domain.Models
+{
+ ///
+ ///UserPassWordLog
+ ///
+ [Table("UserPassWordLog")]
+ public class UserPassWordLog : Entity, IAuditAdd
+ {
+
+
+ ///
+ /// 用户Id
+ ///
+ public Guid UserId { get; set; }
+
+ ///
+ /// 密码
+ ///
+ public string PassWord { get; set; }
+
+ ///
+ /// 创建日期
+ ///
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// 创建人
+ ///
+ public Guid CreateUserId { get; set; }
+
+ }
+
+
+}
diff --git a/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs b/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs
index efd038e73..54522cbbb 100644
--- a/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs
+++ b/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs
@@ -325,7 +325,9 @@ namespace IRaCIS.Core.Infra.EFCore
public virtual DbSet User { get; set; }
- public virtual DbSet TrialSiteUserSurvey { get; set; }
+ public virtual DbSet UserPassWordLog { get; set; }
+
+ public virtual DbSet TrialSiteUserSurvey { get; set; }
public virtual DbSet TrialSiteEquipmentSurvey { get; set; }
public virtual DbSet TrialSiteSurvey { get; set; }
diff --git a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ApiResponseCodeEnum.cs b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ApiResponseCodeEnum.cs
index 58eb41fd6..459ea65fb 100644
--- a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ApiResponseCodeEnum.cs
+++ b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ApiResponseCodeEnum.cs
@@ -33,13 +33,23 @@ namespace IRaCIS.Core.Infrastructure.Extention
CloseCurrentWindows = 6,
+ ///
+ /// IP不一致
+ ///
+ IpDiscrepancy = 7,
- //在其他地方登陆,被迫下线
- LoginInOtherPlace = -1,
+
+ //在其他地方登陆,被迫下线
+ LoginInOtherPlace = -1,
AutoLoginOut = -2,
+ ///
+ /// 需要修改密码
+ ///
+ NeedChangePassWord=-3,
+
//没有带token访问(未登陆)
NoToken = 10,
diff --git a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ResponseOutput.cs b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ResponseOutput.cs
index 0b6e8ea93..af255eeb2 100644
--- a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ResponseOutput.cs
+++ b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ResponseOutput.cs
@@ -128,9 +128,9 @@ namespace IRaCIS.Core.Infrastructure.Extention
// return new ResponseOutput().Ok(data, msg);
//}
- public static IResponseOutput Ok(T data = default, object otherData = default, string msg = "")
+ public static IResponseOutput Ok(T data = default, object otherData = default, string msg = "", ApiResponseCodeEnum code = ApiResponseCodeEnum.OK)
{
- return new ResponseOutput().Ok(data, otherData, msg);
+ return new ResponseOutput().Ok(data, otherData, msg, code);
}
///
/// 成功
diff --git a/IRaCIS.Core.Test/DbHelper.ttinclude b/IRaCIS.Core.Test/DbHelper.ttinclude
index f492fe319..b9c33173c 100644
--- a/IRaCIS.Core.Test/DbHelper.ttinclude
+++ b/IRaCIS.Core.Test/DbHelper.ttinclude
@@ -1,10 +1,10 @@
<#+
public class config
{
- public static readonly string ConnectionString = "Server=123.56.94.154,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true";
+ public static readonly string ConnectionString = "Server=106.14.89.110,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true";
public static readonly string DbDatabase = "Test_IRC";
//表名称用字符串,拼接
- public static readonly string TableName = "EnrollReadingCriterion";
+ public static readonly string TableName = "UserPassWordLog";
//具体文件里面 例如service 可以配置是否分页
}
#>