diff --git a/IRaCIS.Core.Application/Service/Management/UserService.cs b/IRaCIS.Core.Application/Service/Management/UserService.cs index 94fb79e87..fef36d73e 100644 --- a/IRaCIS.Core.Application/Service/Management/UserService.cs +++ b/IRaCIS.Core.Application/Service/Management/UserService.cs @@ -8,6 +8,9 @@ using Panda.DynamicWebApi.Attributes; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Options; using Microsoft.Extensions.Caching.Memory; +using IRaCIS.Core.Infra.Common.Cache; +using Microsoft.Identity.Client; +using static IRaCIS.Core.Domain.Share.StaticData; namespace IRaCIS.Application.Services { @@ -82,7 +85,7 @@ namespace IRaCIS.Application.Services if (oldPwd != null && oldPwd == newPwd) { - //---新密码与旧密码相同。 + //---新密码与旧密码相同。 throw new BusinessValidationFailedException(_localizer["User_NewOldPwdSame"]); } @@ -91,13 +94,13 @@ namespace IRaCIS.Application.Services if (oldPwd != null && dbUser.Password != oldPwd) { - //---旧密码验证失败。 + //---旧密码验证失败。 throw new BusinessValidationFailedException(_localizer["User_OldPwdInvalid"]); } if (dbUser.Password == newPwd) { - //---新密码与旧密码相同。 + //---新密码与旧密码相同。 throw new BusinessValidationFailedException(_localizer["User_NewOldPwdSame"]); } @@ -156,7 +159,7 @@ namespace IRaCIS.Application.Services //检查验证码是否失效 if (verificationRecord.ExpirationTime < DateTime.Now) { - //---验证码已经过期。 + //---验证码已经过期。 return ResponseOutput.NotOk(_localizer["User_VerificationCodeExpired"]); } @@ -358,7 +361,7 @@ namespace IRaCIS.Application.Services if (verificationRecord.ExpirationTime < DateTime.Now) { - //---验证码已经过期。 + //---验证码已经过期。 throw new BusinessValidationFailedException(_localizer["User_VerificationCodeExpired"]); } else //验证码正确 并且 没有超时 @@ -462,7 +465,7 @@ namespace IRaCIS.Application.Services public async Task> GetUserList(UserListQueryDTO param) { var userQueryable = _userRepository.Where(x => x.UserTypeEnum != UserTypeEnum.SuperAdmin) - .WhereIf(!string.IsNullOrWhiteSpace(param.UserName), t => t.UserName.Contains(param.UserName) ) + .WhereIf(!string.IsNullOrWhiteSpace(param.UserName), t => t.UserName.Contains(param.UserName)) .WhereIf(!string.IsNullOrWhiteSpace(param.RealName), t => t.FullName.Contains(param.RealName)) .WhereIf(!string.IsNullOrWhiteSpace(param.Phone), t => t.Phone.Contains(param.Phone)) .WhereIf(!string.IsNullOrWhiteSpace(param.OrganizationName), t => t.OrganizationName.Contains(param.OrganizationName)) @@ -613,6 +616,37 @@ namespace IRaCIS.Application.Services [NonDynamicMethod] public async Task> Login(string userName, string password) { + + const string cachePrefix = "login-failures:"; + const int maxFailures = 3; + const int lockoutMinutes = 1; + + // 生成缓存键 + string cacheKey = $"{cachePrefix}{userName}"; + + // 从缓存中获取登录失败次数 + int? failCount = _cache.Get(cacheKey); + + + if (failCount == null) + { + failCount = 0; + } + + //每次登录 都重置缓存时间 + _cache.Set(cacheKey, failCount, TimeSpan.FromMinutes(lockoutMinutes)); + + + + if (failCount >= maxFailures) + { + throw new BusinessValidationFailedException($"密码连续错误3次,当前账号已被限制登录,请等待 {lockoutMinutes} 分钟后再试。"); + } + + + + + var userLoginReturnModel = new LoginReturnDTO(); @@ -620,21 +654,32 @@ namespace IRaCIS.Application.Services if (loginUser == null) { - //此处下面 代码 为了支持医生也能登录 而且前端不加选择到底是管理用户 还是医生用户 奇怪的需求 无法理解 - var loginDoctor = await _doctorRepository.Where(u => u.Phone == userName && u.Password == password).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefaultAsync(); + #region 屏蔽代码,现在没用到 + ////此处下面 代码 为了支持医生也能登录 而且前端不加选择到底是管理用户 还是医生用户 奇怪的需求 无法理解 - if (loginDoctor == null) - { - return ResponseOutput.NotOk(_localizer["User_CheckNameOrPw"], new LoginReturnDTO()); + //var loginDoctor = await _doctorRepository.Where(u => u.Phone == userName && u.Password == password).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefaultAsync(); - } + //if (loginDoctor == null) + //{ + // return ResponseOutput.NotOk(_localizer["User_CheckNameOrPw"], new LoginReturnDTO()); + //} + //userLoginReturnModel.BasicInfo = loginDoctor; + + //登录 清除缓存 + //_cache.Remove(userLoginReturnModel.BasicInfo.Id.ToString()); + //return ResponseOutput.Ok(userLoginReturnModel); + + #endregion + + + //错误次数累加 + failCount++; + _cache.Set(cacheKey, failCount, TimeSpan.FromMinutes(lockoutMinutes)); + + return ResponseOutput.NotOk(_localizer["User_CheckNameOrPw"], new LoginReturnDTO()); - userLoginReturnModel.BasicInfo = loginDoctor; - // 登录 清除缓存 - _cache.Remove(userLoginReturnModel.BasicInfo.Id.ToString()); - return ResponseOutput.Ok(userLoginReturnModel); } @@ -644,6 +689,12 @@ namespace IRaCIS.Application.Services return ResponseOutput.NotOk(_localizer["User_Disabled"], new LoginReturnDTO()); } + + //登录成功 清除缓存 + _cache.Set(cacheKey, 0, TimeSpan.FromMinutes(lockoutMinutes)); + + + userLoginReturnModel.BasicInfo = loginUser; // 登录 清除缓存 @@ -652,5 +703,35 @@ namespace IRaCIS.Application.Services } + + + + //private bool loginIsLocked(string userName) + //{ + + // //if (failCount == null) + // //{ + // // failCount = 0; + // //} + // //else + // //{ + // // failCount++; + // //} + + // //// 更新缓存中的登录失败次数 + // //_cache.Set(cacheKey, failCount, TimeSpan.FromMinutes(lockoutMinutes)); + + // //if (failCount >= maxFailures) + // //{ + // // // 如果登录失败次数达到了 3 次,则锁定用户 + // // _cache.Set(cacheKey + ":locked", true, TimeSpan.FromMinutes(lockoutMinutes)); + // //} + + + + + // //return isLocked; + //} + } } diff --git a/IRaCIS.Core.Application/Service/Reading/AdditionalEvaluate/SubjectCriteriaEvaluationService.cs b/IRaCIS.Core.Application/Service/Reading/AdditionalEvaluate/SubjectCriteriaEvaluationService.cs index 5338cedf1..e7e9a8882 100644 --- a/IRaCIS.Core.Application/Service/Reading/AdditionalEvaluate/SubjectCriteriaEvaluationService.cs +++ b/IRaCIS.Core.Application/Service/Reading/AdditionalEvaluate/SubjectCriteriaEvaluationService.cs @@ -125,7 +125,8 @@ namespace IRaCIS.Core.Application.Service Id = subjectCriteriaEvaluation.Id, TrialReadingCriterionId = inQuery.TrialReadingCriterionId, - IsImageFiltering = subjectCriteriaEvaluation.SubjectCriteriaEvaluationVisitFilterList.Any(t => t.ImageFilterState == ImageFilterState.None), + IsImageFiltering = subject.SubjectCriteriaEvaluationVisitFilterList.Any(t => t.TrialReadingCriterionId== inQuery.TrialReadingCriterionId + && t.ImageFilterState == ImageFilterState.None), IsJoinEvaluation = subjectCriteriaEvaluation.IsJoinEvaluation, diff --git a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialConfigService.cs b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialConfigService.cs index 6d583a687..630ce5576 100644 --- a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialConfigService.cs +++ b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialConfigService.cs @@ -640,7 +640,7 @@ namespace IRaCIS.Core.Application AdditionalAssessment additional = new AdditionalAssessment(); var addTypeList = additional.GetSystemDefeaultAdditionalAssessmentList(updateItem.CriterionType, updateItem.AdditionalAssessmentType); - if(! await _readingQuestionTrialRepository.AnyAsync(t => t.ReadingQuestionCriterionTrialId == updateItem.TrialReadingCriterionId && t.IsAdditional==true)) + if(!await _readingQuestionTrialRepository.AsQueryable().IgnoreQueryFilters().AnyAsync(t => t.ReadingQuestionCriterionTrialId == updateItem.TrialReadingCriterionId && t.IsAdditional==true)) { foreach (var addType in addTypeList) { diff --git a/IRaCIS.Core.Domain/Allocation/VisitTask.cs b/IRaCIS.Core.Domain/Allocation/VisitTask.cs index 5e070eb5b..1f4ebc15f 100644 --- a/IRaCIS.Core.Domain/Allocation/VisitTask.cs +++ b/IRaCIS.Core.Domain/Allocation/VisitTask.cs @@ -121,10 +121,6 @@ namespace IRaCIS.Core.Domain.Models public Subject Subject { get; set; } - [JsonIgnore] - - public SubjectCriteriaEvaluationVisitFilter SubjectCriteriaEvaluationVisitFilter { get; set;} - [JsonIgnore] public List TaskMedicalReviewList { get; set; } diff --git a/IRaCIS.Core.Domain/Reading/AdditionalEvaluate/SubjectCriteriaEvaluation.cs b/IRaCIS.Core.Domain/Reading/AdditionalEvaluate/SubjectCriteriaEvaluation.cs index 1a6fcafca..e7432ddcb 100644 --- a/IRaCIS.Core.Domain/Reading/AdditionalEvaluate/SubjectCriteriaEvaluation.cs +++ b/IRaCIS.Core.Domain/Reading/AdditionalEvaluate/SubjectCriteriaEvaluation.cs @@ -24,6 +24,9 @@ namespace IRaCIS.Core.Domain.Models [ForeignKey("TrialReadingCriterionId")] public ReadingQuestionCriterionTrial TrialReadingCriterion { get; set; } + [JsonIgnore] + public List SubjectCriteriaEvaluationVisitFilterList { get; set; } + /// /// SubjectId /// @@ -67,8 +70,7 @@ namespace IRaCIS.Core.Domain.Models public DateTime UpdateTime { get; set; } - [JsonIgnore] - public List SubjectCriteriaEvaluationVisitFilterList { get; set; } + diff --git a/IRaCIS.Core.Domain/Reading/AdditionalEvaluate/SubjectCriteriaEvaluationVisitFilter.cs b/IRaCIS.Core.Domain/Reading/AdditionalEvaluate/SubjectCriteriaEvaluationVisitFilter.cs index baeef00f4..91f03106c 100644 --- a/IRaCIS.Core.Domain/Reading/AdditionalEvaluate/SubjectCriteriaEvaluationVisitFilter.cs +++ b/IRaCIS.Core.Domain/Reading/AdditionalEvaluate/SubjectCriteriaEvaluationVisitFilter.cs @@ -18,12 +18,14 @@ namespace IRaCIS.Core.Domain.Models public class SubjectCriteriaEvaluationVisitFilter : Entity, IAuditUpdate, IAuditAdd { - [JsonIgnore] + //[JsonIgnore] - public List SubjectCriterionTaskList { get; set; } + //public List SubjectCriterionTaskList { get; set; } [JsonIgnore] [ForeignKey("TrialReadingCriterionId")] public ReadingQuestionCriterionTrial TrialReadingCriterion { get; set; } + + [JsonIgnore] public SubjectCriteriaEvaluation SubjectCriteriaEvaluation { get; set; } diff --git a/IRaCIS.Core.Domain/Visit/Subject.cs b/IRaCIS.Core.Domain/Visit/Subject.cs index 66a00fed3..0ad19bb43 100644 --- a/IRaCIS.Core.Domain/Visit/Subject.cs +++ b/IRaCIS.Core.Domain/Visit/Subject.cs @@ -12,6 +12,8 @@ namespace IRaCIS.Core.Domain.Models [Table("Subject")] public class Subject : Entity, IAuditAdd, IAuditUpdate, ISoftDelete { + + [JsonIgnore] public List SubjectVisitList { get; set; } = new List(); [JsonIgnore] diff --git a/IRaCIS.Core.Infra.EFCore/EntityConfigration/TrialSiteConfigration.cs b/IRaCIS.Core.Infra.EFCore/EntityConfigration/TrialSiteConfigration.cs index 2bfb1dbca..1306cbbf3 100644 --- a/IRaCIS.Core.Infra.EFCore/EntityConfigration/TrialSiteConfigration.cs +++ b/IRaCIS.Core.Infra.EFCore/EntityConfigration/TrialSiteConfigration.cs @@ -36,18 +36,18 @@ namespace IRaCIS.Core.Infra.EFCore.EntityConfigration } } - public class SubjectCriteriaEvaluationVisitFilterConfigration : IEntityTypeConfiguration - { + //public class SubjectCriteriaEvaluationVisitFilterConfigration : IEntityTypeConfiguration + //{ - public void Configure(EntityTypeBuilder builder) - { - builder - .HasMany(s => s.SubjectCriterionTaskList) - .WithOne(c => c.SubjectCriteriaEvaluationVisitFilter) - .HasForeignKey(s => new { s.SubjectId, s.TrialReadingCriterionId }) - .HasPrincipalKey(c => new { c.SubjectId, c.TrialReadingCriterionId }); + // public void Configure(EntityTypeBuilder builder) + // { + // builder + // .HasMany(s => s.SubjectCriterionTaskList) + // .WithOne(c => c.SubjectCriteriaEvaluationVisitFilter) + // .HasForeignKey(s => new { s.SubjectId, s.TrialReadingCriterionId }) + // .HasPrincipalKey(c => new { c.SubjectId, c.TrialReadingCriterionId }); - } - } + // } + //} }