diff --git a/IRaCIS.Core.API/Controllers/ExtraController.cs b/IRaCIS.Core.API/Controllers/ExtraController.cs index 97804aa3e..95fba4ab5 100644 --- a/IRaCIS.Core.API/Controllers/ExtraController.cs +++ b/IRaCIS.Core.API/Controllers/ExtraController.cs @@ -32,6 +32,7 @@ using IRaCIS.Core.Application.Contracts; using LoginReturnDTO = IRaCIS.Application.Contracts.LoginReturnDTO; using DocumentFormat.OpenXml.Spreadsheet; using AutoMapper.QueryableExtensions; +using NetTopologySuite.Algorithm; namespace IRaCIS.Api.Controllers { @@ -108,7 +109,7 @@ namespace IRaCIS.Api.Controllers { //MFA 邮箱验证 前端传递用户Id 和MFACode - if (loginUser.UserId != null && _verifyConfig.CurrentValue.OpenLoginMFA) + if (loginUser.UserId != null && _verifyConfig.CurrentValue.OpenLoginMFA) { Guid userId = (Guid)loginUser.UserId; @@ -226,23 +227,7 @@ namespace IRaCIS.Api.Controllers var email = returnModel.Data.BasicInfo.EMail; - #region 隐藏Email - // 找到 "@" 符号的位置 - int atIndex = email.IndexOf('@'); - - // 替换 "@" 符号前的中间两位为星号 - string visiblePart = email.Substring(0, atIndex); - - int startIndex = (visiblePart.Length - 2) / 2; - - // 替换中间两位字符为星号 - string hiddenPartBeforeAt = visiblePart.Substring(0, startIndex) + "**" + visiblePart.Substring(startIndex + 2); - - string afterAt = email.Substring(atIndex + 1); - - // 组合隐藏和可见部分 - string hiddenEmail = hiddenPartBeforeAt + "@" + afterAt; - #endregion + var hiddenEmail = EmailMaskHelper.MaskEmail(email); returnModel.Data.BasicInfo.EMail = hiddenEmail; diff --git a/IRaCIS.Core.API/IRaCIS.Core.API.csproj b/IRaCIS.Core.API/IRaCIS.Core.API.csproj index 8bdddbe5f..5a7be3fe9 100644 --- a/IRaCIS.Core.API/IRaCIS.Core.API.csproj +++ b/IRaCIS.Core.API/IRaCIS.Core.API.csproj @@ -71,6 +71,7 @@ + diff --git a/IRaCIS.Core.API/Progranm.cs b/IRaCIS.Core.API/Progranm.cs index 50cb855b4..40ffb2743 100644 --- a/IRaCIS.Core.API/Progranm.cs +++ b/IRaCIS.Core.API/Progranm.cs @@ -28,6 +28,7 @@ using FellowOakDicom.Network; using IRaCIS.Core.Application.Service.ImageAndDoc; using IP2Region.Net.Abstractions; using IP2Region.Net.XDB; +using IRaCIS.Core.Application.BusinessFilter; #region 获取环境变量 @@ -104,11 +105,9 @@ builder.Services.AddControllers(options => options.Filters.Add(); options.Filters.Add(); options.Filters.Add(); + options.Filters.Add(10); + options.Filters.Add(); - if (_configuration.GetSection("BasicSystemConfig").GetValue("OpenLoginLimit")) - { - options.Filters.Add(); - } }) .AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理 @@ -117,6 +116,8 @@ builder.Services.AddOptions().Configure(_configuration.Ge builder.Services.AddOptions().Configure(_configuration.GetSection("BasicSystemConfig")); builder.Services.AddOptions().Configure(_configuration.GetSection("AliyunOSS")); builder.Services.AddOptions().Configure(_configuration.GetSection("ObjectStoreService")); +builder.Services.AddOptions().Configure(_configuration.GetSection("EncrypteResponseConfig")); + //动态WebApi + UnifiedApiResultFilter 省掉控制器代码 @@ -297,7 +298,7 @@ try - var server = DicomServerFactory.Create(11112,userState: app.Services); + var server = DicomServerFactory.Create(11112, userState: app.Services); app.Run(); diff --git a/IRaCIS.Core.API/_ServiceExtensions/hangfireSetup.cs b/IRaCIS.Core.API/_ServiceExtensions/hangfireSetup.cs index 00b718e2c..e2dc37494 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/hangfireSetup.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/hangfireSetup.cs @@ -3,6 +3,7 @@ using Hangfire.SqlServer; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; +using System.Runtime.InteropServices; namespace IRaCIS.Core.API { @@ -14,19 +15,29 @@ namespace IRaCIS.Core.API services.AddHangfire(hangFireConfig => { - - //hangFireConfig.UseInMemoryStorage(); - - //指定存储介质 - hangFireConfig.UseSqlServerStorage(hangFireConnStr, new SqlServerStorageOptions() + //本地window 调试 使用内存,服务器部署使用数据库,防止服务器任务调度到本地 + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - SchemaName = "dbo", - CommandBatchMaxTimeout = TimeSpan.FromMinutes(5), - SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5), - QueuePollInterval = TimeSpan.Zero, - UseRecommendedIsolationLevel = true, - DisableGlobalLocks = true - }); + hangFireConfig.UseInMemoryStorage(); + + } + else + { + //指定存储介质 + hangFireConfig.UseSqlServerStorage(hangFireConnStr, new SqlServerStorageOptions() + { + SchemaName = "dbo", + CommandBatchMaxTimeout = TimeSpan.FromMinutes(5), + SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5), + QueuePollInterval = TimeSpan.Zero, + UseRecommendedIsolationLevel = true, + DisableGlobalLocks = true + }); + } + + + + //hangFireConfig.UseTagsWithSql(); //nuget引入Hangfire.Tags.SqlServer //.UseHangfireHttpJob(); diff --git a/IRaCIS.Core.API/appsettings.json b/IRaCIS.Core.API/appsettings.json index b6d0f4125..59dd671c2 100644 --- a/IRaCIS.Core.API/appsettings.json +++ b/IRaCIS.Core.API/appsettings.json @@ -92,5 +92,12 @@ "DefaultPassword": "123456", "DefaultInternalOrganizationName": "ExtImaging", "ImageShareExpireDays": 10 + }, + + "EncrypteResponseConfig": { + "IsEnable": true, + "ApiPathList": [ + "/test/get" + ] } } \ No newline at end of file diff --git a/IRaCIS.Core.Application/BusinessFilter/EncreptApiResultFilter.cs b/IRaCIS.Core.Application/BusinessFilter/EncreptApiResultFilter.cs new file mode 100644 index 000000000..fd58ae885 --- /dev/null +++ b/IRaCIS.Core.Application/BusinessFilter/EncreptApiResultFilter.cs @@ -0,0 +1,71 @@ +using IRaCIS.Core.Domain.Share; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Application.BusinessFilter +{ + public class EncreptApiResultFilter : IAsyncResultFilter + { + + private readonly IOptionsMonitor _encreptResponseMonitor; + + public EncreptApiResultFilter(IOptionsMonitor encreptResponseMonitor) + { + _encreptResponseMonitor = encreptResponseMonitor; + } + + public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) + { + + if(_encreptResponseMonitor.CurrentValue.IsEnable) + { + + if (context.Result is ObjectResult objectResult) + { + var statusCode = objectResult.StatusCode ?? context.HttpContext.Response.StatusCode; + + var objectValue = objectResult.Value; + + + if (objectValue is IResponseOutput) + { + var responseOutput = objectValue as IResponseOutput; + + var path = context.HttpContext?.Request.Path.Value?.ToLower(); + + + if(!string.IsNullOrEmpty(path) && path.Length>5 && _encreptResponseMonitor.CurrentValue.ApiPathList.Contains(path.ToLower())) + { + + if(responseOutput.IsSuccess) + { + responseOutput.Code = ApiResponseCodeEnum.ResultEncrepted; + responseOutput.Data = JsonConvert.SerializeObject(Convert.ToBase64String(Encoding.UTF8.GetBytes(responseOutput.Data.ToString()))); + + objectResult.Value = responseOutput; + } + + } + + } + + + + } + } + + + + + await next.Invoke(); + + } + } +} diff --git a/IRaCIS.Core.Application/BusinessFilter/UnifiedApiResultFilter.cs b/IRaCIS.Core.Application/BusinessFilter/UnifiedApiResultFilter.cs index a41c659b1..9e5fdf591 100644 --- a/IRaCIS.Core.Application/BusinessFilter/UnifiedApiResultFilter.cs +++ b/IRaCIS.Core.Application/BusinessFilter/UnifiedApiResultFilter.cs @@ -8,8 +8,9 @@ namespace IRaCIS.Application.Services.BusinessFilter /// 统一返回前端数据包装,之前在控制器包装,现在修改为动态Api 在ResultFilter这里包装,减少重复冗余代码 /// by zhouhang 2021.09.12 周末 /// - public class UnifiedApiResultFilter : Attribute, IAsyncResultFilter - { + public class UnifiedApiResultFilter : Attribute, IAsyncResultFilter + { + /// /// 异步版本 /// @@ -26,15 +27,6 @@ namespace IRaCIS.Application.Services.BusinessFilter //是200 并且没有包装 那么包装结果 if (statusCode == 200 && !(objectResult.Value is IResponseOutput)) { - //if (objectResult.Value == null) - //{ - // var apiResponse = ResponseOutput.DBNotExist(); - - // objectResult.Value = apiResponse; - // objectResult.DeclaredType = apiResponse.GetType(); - //} - //else - //{ var type = objectResult.Value?.GetType(); @@ -64,8 +56,6 @@ namespace IRaCIS.Application.Services.BusinessFilter objectResult.DeclaredType = apiResponse.GetType(); } - - //} } //如果不是200 是IResponseOutput 不处理 diff --git a/IRaCIS.Core.Application/Helper/EmailMaskHelper.cs b/IRaCIS.Core.Application/Helper/EmailMaskHelper.cs new file mode 100644 index 000000000..027c74523 --- /dev/null +++ b/IRaCIS.Core.Application/Helper/EmailMaskHelper.cs @@ -0,0 +1,44 @@ +using NPOI.SS.Formula.Functions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Application.Helper +{ + public static class EmailMaskHelper + { + + //显示位数:3分之2的位数,向上取整 + //取哪几个个值:最后一位和前面几位 + //其他:3个***。 + //比如:hlj23@126.com + //为:hlj***3@126.com + + //he@126.com + //为:h*** e@126.com + + public static string MaskEmail(string email) + { + + // 找到 "@" 符号的位置 + int atIndex = email.IndexOf('@'); + + string visiblePartBefore = email.Substring(0, atIndex); + + string afterAt = email.Substring(atIndex + 1); + + int visibleLength = (int)Math.Ceiling((double)visiblePartBefore.Length * 2 / 3); + + // 替换中间两位字符为星号 + string hiddenPartBeforeAt = visiblePartBefore.Substring(0, visibleLength - 1) + "***" + visiblePartBefore.Last(); + + + // 组合隐藏和可见部分 + string hiddenEmail = hiddenPartBeforeAt + "@" + afterAt; + + return hiddenEmail; + } + } +} diff --git a/IRaCIS.Core.Application/Service/Common/MailService.cs b/IRaCIS.Core.Application/Service/Common/MailService.cs index e2da0075e..e34361d6f 100644 --- a/IRaCIS.Core.Application/Service/Common/MailService.cs +++ b/IRaCIS.Core.Application/Service/Common/MailService.cs @@ -256,7 +256,7 @@ namespace IRaCIS.Application.Services var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr), - "", + "Sir/Madam", //---您正在进行邮箱重置密码操作 _localizer["Mail_ResettingPassword"], verificationCode @@ -300,7 +300,7 @@ namespace IRaCIS.Application.Services var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr), - "Sir or Madam", + "Sir/Madam", //---您正在参与展影医疗IRC项目 _localizer["Mail_IRCProject", companyName], verificationCode @@ -342,7 +342,7 @@ namespace IRaCIS.Application.Services var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr), - "Sir or Madam", + "Sir/Madam", //---您正在参与展影医疗IRC项目中心调研工作 _localizer["Mail_CenterResearchReminder", companyName], verificationCode diff --git a/IRaCIS.Core.Application/Service/Management/UserService.cs b/IRaCIS.Core.Application/Service/Management/UserService.cs index f103313cf..7aab3e7b6 100644 --- a/IRaCIS.Core.Application/Service/Management/UserService.cs +++ b/IRaCIS.Core.Application/Service/Management/UserService.cs @@ -18,6 +18,7 @@ using LoginReturnDTO = IRaCIS.Application.Contracts.LoginReturnDTO; using IRaCIS.Core.Application.Auth; using BeetleX.Redis.Commands; using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Application.Helper; namespace IRaCIS.Application.Services { @@ -676,7 +677,8 @@ namespace IRaCIS.Application.Services await _mailVerificationService.SenMFAVerifyEmail(userId, userInfo.FullName, userInfo.EMail, verificationCode, (UserMFAType)mfaType); - return ResponseOutput.Ok(); + var hiddenEmail = EmailMaskHelper.MaskEmail(userInfo.EMail); + return ResponseOutput.Ok(hiddenEmail); } /// diff --git a/IRaCIS.Core.Application/TestService.cs b/IRaCIS.Core.Application/TestService.cs index f00d2ac7a..08fbc3a60 100644 --- a/IRaCIS.Core.Application/TestService.cs +++ b/IRaCIS.Core.Application/TestService.cs @@ -261,9 +261,12 @@ namespace IRaCIS.Application.Services [AllowAnonymous] - public async Task testwwwww([FromServices] IWebHostEnvironment env) + public async Task testEmail([FromServices] IWebHostEnvironment env ,string email) { - await Task.CompletedTask; + + var hiddenEmail = EmailMaskHelper.MaskEmail(email); + + return hiddenEmail; } diff --git a/IRaCIS.Core.Domain/_Config/_AppSettings.cs b/IRaCIS.Core.Domain/_Config/_AppSettings.cs index 80aed90e8..a4833050b 100644 --- a/IRaCIS.Core.Domain/_Config/_AppSettings.cs +++ b/IRaCIS.Core.Domain/_Config/_AppSettings.cs @@ -1,6 +1,7 @@ using IRaCIS.Core.Domain.Models; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.Json; +using System.Collections.Generic; namespace IRaCIS.Core.Domain.Share { @@ -19,7 +20,7 @@ namespace IRaCIS.Core.Domain.Share public int LoginMaxFailCount { get; set; } - public int LoginFailLockMinutes { get; set; } + public int LoginFailLockMinutes { get; set; } public int AutoLoginOutMinutes { get; set; } @@ -39,9 +40,9 @@ namespace IRaCIS.Core.Domain.Share public class SystemEmailSendConfig { - public int Port { get; set; } + public int Port { get; set; } - public string Host { get; set; } + public string Host { get; set; } public string FromEmail { get; set; } @@ -66,6 +67,13 @@ namespace IRaCIS.Core.Domain.Share } + public class EncreptResponseOption + { + public bool IsEnable { get; set; } + + public List ApiPathList { get; set; } + } + /// /// 项目基础配置规则 @@ -89,7 +97,7 @@ namespace IRaCIS.Core.Domain.Share public static string SystemSiteCodePrefix { get; set; } - public static string BlindTaskPrefix { get; set; } + public static string BlindTaskPrefix { get; set; } /// /// 用户默认密码 @@ -104,7 +112,7 @@ namespace IRaCIS.Core.Domain.Share { Path = "appsettings.json", ReloadOnChange = true - }) + }) .Build(); DoctorCodePrefix = configuration.GetSection("IRaCISBasicConfig").GetValue("DoctorCodePrefix"); @@ -112,7 +120,7 @@ namespace IRaCIS.Core.Domain.Share QCChallengeCodePrefix = configuration.GetSection("IRaCISBasicConfig").GetValue("QCChallengeCodePrefix"); NoneDicomStudyCodePrefix = configuration.GetSection("IRaCISBasicConfig").GetValue("NoneDicomStudyCodePrefix"); DicomStudyCodePrefix = configuration.GetSection("IRaCISBasicConfig").GetValue("DicomStudyCodePrefix"); - DefaultPassword= configuration.GetSection("IRaCISBasicConfig").GetValue("DefaultPassword"); + DefaultPassword = configuration.GetSection("IRaCISBasicConfig").GetValue("DefaultPassword"); SystemSiteCodePrefix = configuration.GetSection("IRaCISBasicConfig").GetValue("SystemSiteCodePrefix"); DefaultInternalOrganizationName = configuration.GetSection("IRaCISBasicConfig").GetValue("DefaultInternalOrganizationName"); @@ -125,7 +133,7 @@ namespace IRaCIS.Core.Domain.Share //获取实体编码字符串 - public static string GetCodeStr(int codeInt ,string typeStr) + public static string GetCodeStr(int codeInt, string typeStr) { switch (typeStr) { @@ -139,7 +147,7 @@ namespace IRaCIS.Core.Domain.Share case nameof(QCChallenge): - return QCChallengeCodePrefix+ codeInt.ToString("D5"); + return QCChallengeCodePrefix + codeInt.ToString("D5"); case nameof(NoneDicomStudy): @@ -164,5 +172,5 @@ namespace IRaCIS.Core.Domain.Share } - + } \ No newline at end of file diff --git a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ApiResponseCodeEnum.cs b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ApiResponseCodeEnum.cs index 459ea65fb..a2d88b1c8 100644 --- a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ApiResponseCodeEnum.cs +++ b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ApiResponseCodeEnum.cs @@ -54,7 +54,9 @@ namespace IRaCIS.Core.Infrastructure.Extention NoToken = 10, //带了Token,但是没有相应权限(该用户类型不能做) - HaveTokenNotAccess = 11 + HaveTokenNotAccess = 11, + + ResultEncrepted=12 } diff --git a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/IResponseOutput.cs b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/IResponseOutput.cs index 9c713a8a0..13b15698a 100644 --- a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/IResponseOutput.cs +++ b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/IResponseOutput.cs @@ -27,7 +27,7 @@ /// /// 返回数据 /// - T Data { get; } + T Data { get; set; } } //public interface IResponseOutput : IResponseOutput diff --git a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ResponseOutput.cs b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ResponseOutput.cs index af255eeb2..74325db91 100644 --- a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ResponseOutput.cs +++ b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ResponseOutput.cs @@ -25,7 +25,7 @@ namespace IRaCIS.Core.Infrastructure.Extention /// 数据 兼顾以前 Json序列化的时候返回属性名为“Result” /// [JsonProperty("Result")] - public T Data { get; private set; } + public T Data { get; set; } [JsonProperty("OtherInfo")]