@@ -30,6 +30,8 @@ using IRaCIS.Core.Application.Helper;
using Microsoft.Extensions.Options ;
using IRaCIS.Core.Application.Contracts ;
using LoginReturnDTO = IRaCIS . Application . Contracts . LoginReturnDTO ;
using DocumentFormat.OpenXml.Spreadsheet ;
using AutoMapper.QueryableExtensions ;
namespace IRaCIS.Api.Controllers
{
@@ -53,8 +55,8 @@ namespace IRaCIS.Api.Controllers
/// <param name="doctorId"></param>
/// <returns></returns>
[HttpGet, Route("doctor/getDetail/{doctorId:guid}")]
public async Task < IResponseOutput < DoctorDetailDTO > > GetDoctorDetail ( [ FromServices ] IAttachmentService attachmentService , [ FromServices ] IDoctorService _doctorService ,
public async Task < IResponseOutput < DoctorDetailDTO > > GetDoctorDetail ( [ FromServices ] IAttachmentService attachmentService , [ FromServices ] IDoctorService _doctorService ,
[FromServices] IEducationService _educationService , [ FromServices ] ITrialExperienceService _trialExperienceService ,
[FromServices] IResearchPublicationService _researchPublicationService , [ FromServices ] IVacationService _vacationService , Guid doctorId )
@@ -66,7 +68,7 @@ namespace IRaCIS.Api.Controllers
var doctorDetail = new DoctorDetailDTO
{
AuditView = await _doctorService . GetAuditState ( doctorId ) ,
AuditView = await _doctorService . GetAuditState ( doctorId ) ,
BasicInfoView = await _doctorService . GetBasicInfo ( doctorId ) ,
EmploymentView = await _doctorService . GetEmploymentInfo ( doctorId ) ,
AttachmentList = await attachmentService . GetAttachments ( doctorId ) ,
@@ -77,7 +79,7 @@ namespace IRaCIS.Api.Controllers
TrialExperienceView = await _trialExperienceService . GetTrialExperience ( doctorId ) ,
ResearchPublicationView = await _researchPublicationService . GetResearchPublication ( doctorId ) ,
SpecialtyView = await _doctorService . GetSpecialtyInfo ( doctorId ) ,
SpecialtyView = await _doctorService . GetSpecialtyInfo ( doctorId ) ,
InHoliday = ( await _vacationService . OnVacation ( doctorId ) ) . IsSuccess ,
IntoGroupInfo = _doctorService . GetDoctorIntoGroupInfo ( doctorId ) ,
SowList = sowList ,
@@ -96,80 +98,30 @@ namespace IRaCIS.Api.Controllers
/// <summary> 系统用户登录接口[New] </summary>
[HttpPost, Route("user/login")]
[AllowAnonymous]
public async Task < IResponseOutput < LoginReturnDTO > > Login ( UserLoginDTO loginUser , [ FromServices ] IEasyCachingProvider provider , [ FromServices ] IUserService _userService ,
[FromServices] ITokenService _tokenService ,
[FromServices] IReadingImageTaskService readingImageTaskService ,
[FromServices] IConfiguration configuration )
public async Task < IResponseOutput > Login ( UserLoginDTO loginUser ,
[FromServices] IEasyCachingProvider provider ,
[FromServices] IUserService _userService ,
[FromServices] ITokenService _tokenService ,
[FromServices] IReadingImageTaskService readingImageTaskService ,
IOptionsMonitor < ServiceVerifyConfigOption > _verifyConfig ,
IMailVerificationService _mailVerificationService )
{
var returnModel = await _userService . Login ( loginUser . UserName , loginUser . Password ) ;
if ( returnModel . IsSuccess )
//MFA 邮箱验证 前端传递用户Id 和MFACode
if ( loginUser . UserId ! = null & & ! string . IsNullOrEmpty ( loginUser . MFACode ) & & _verifyConfig . CurrentValue . OpenLoginMFA )
{
#region GRPC 调 用 鉴 权 中 心 , 因 为 服 务 器 IIS问题 http / 2 故 而 没 法 使 用
Guid userId = ( Guid ) loginUser . UserId ;
////重试策略
//var defaultMethodConfig = new MethodConfig
//{
// Names = { MethodName.Default },
// RetryPolicy = new RetryPolicy
// {
// MaxAttempts = 3,
// InitialBackoff = TimeSpan.FromSeconds(1),
// MaxBackoff = TimeSpan.FromSeconds(5),
// BackoffMultiplier = 1.5,
// RetryableStatusCodes = { Grpc.Core.StatusCode.Unavailable }
// }
//};
//验证MFA 编码是否有问题
//#region unable to trust the certificate then the gRPC client can be configured to ignore the invalid certificate
await _userService . VerifyMFACodeAsync ( userId , loginUser . MFACode ) ;
//var httpHandler = new HttpClientHandler();
//// Return `true` to allow certificates that are untrusted/invalid
//httpHandler.ServerCertificateCustomValidationCallback =
// HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var basicInfo = await _userService . GetUserBasicInfo ( userId ) ;
var loginReturn = new LoginReturnDTO ( ) { BasicInfo = basicInfo } ;
//////这一句是让grpc支持本地 http 如果本地访问部署在服务器上,那么是访问不成功的
//AppContext.SetSwitch(
// "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
loginReturn . JWTStr = _tokenService . GetToken ( IRaCISClaims . Create ( loginReturn . BasicInfo ) ) ;
//#endregion
//var grpcAdress = configuration.GetValue<string>("GrpcAddress");
////var grpcAdress = "http://localhost:7200";
//var channel = GrpcChannel.ForAddress(grpcAdress, new GrpcChannelOptions
//{
// HttpHandler = httpHandler,
// ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
//});
////var channel = GrpcChannel.ForAddress(grpcAdress);
//var grpcClient = new TokenGrpcService.TokenGrpcServiceClient(channel);
//var userInfo = returnModel.Data.BasicInfo;
//var tokenResponse = grpcClient.GetUserToken(new GetTokenReuqest()
//{
// Id = userInfo.Id.ToString(),
// ReviewerCode = userInfo.ReviewerCode,
// IsAdmin = userInfo.IsAdmin,
// RealName = userInfo.RealName,
// UserTypeEnumInt = (int)userInfo.UserTypeEnum,
// UserTypeShortName = userInfo.UserTypeShortName,
// UserName = userInfo.UserName
//});
//returnModel.Data.JWTStr = tokenResponse.Token;
#endregion
returnModel . Data . JWTStr = _tokenService . GetToken ( IRaCISClaims . Create ( returnModel . Data . BasicInfo ) ) ;
// 创建一个 CookieOptions 对象,用于设置 Cookie 的属性
var option = new CookieOptions
@@ -180,20 +132,161 @@ namespace IRaCIS.Api.Controllers
Secure = false // 确保 cookie 只能通过 HTTPS 访问
} ;
HttpContext . Response . Cookies . Append ( "access_token" , returnModel . Data . JWTStr , option ) ;
HttpContext . Response . Cookies . Append ( "access_token" , loginReturn . JWTStr , option ) ;
// 验证阅片休息时间
await readingImageTaskService . ResetReadingRestTime ( userId ) ;
await provider . SetAsync ( userId . ToString ( ) , loginReturn . JWTStr , TimeSpan . FromDays ( 7 ) ) ;
await provider . SetAsync ( $"{userId.ToString()}_Online" , DateTime . Now . ToString ( "yyyy-MM-dd HH:mm:ss" ) , TimeSpan . FromMinutes ( _verifyConfig . CurrentValue . AutoLoginOutMinutes ) ) ;
return ResponseOutput . Ok ( loginReturn ) ;
}
else
{
var returnModel = await _userService . Login ( loginUser . UserName , loginUser . Password ) ;
if ( returnModel . IsSuccess )
{
#region GRPC 调 用 鉴 权 中 心 , 因 为 服 务 器 IIS问题 http / 2 故 而 没 法 使 用
////重试策略
//var defaultMethodConfig = new MethodConfig
//{
// Names = { MethodName.Default },
// RetryPolicy = new RetryPolicy
// {
// MaxAttempts = 3,
// InitialBackoff = TimeSpan.FromSeconds(1),
// MaxBackoff = TimeSpan.FromSeconds(5),
// BackoffMultiplier = 1.5,
// RetryableStatusCodes = { Grpc.Core.StatusCode.Unavailable }
// }
//};
//#region unable to trust the certificate then the gRPC client can be configured to ignore the invalid certificate
//var httpHandler = new HttpClientHandler();
//// Return `true` to allow certificates that are untrusted/invalid
//httpHandler.ServerCertificateCustomValidationCallback =
// HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
//////这一句是让grpc支持本地 http 如果本地访问部署在服务器上,那么是访问不成功的
//AppContext.SetSwitch(
// "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
//#endregion
//var grpcAdress = configuration.GetValue<string>("GrpcAddress");
////var grpcAdress = "http://localhost:7200";
//var channel = GrpcChannel.ForAddress(grpcAdress, new GrpcChannelOptions
//{
// HttpHandler = httpHandler,
// ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
//});
////var channel = GrpcChannel.ForAddress(grpcAdress);
//var grpcClient = new TokenGrpcService.TokenGrpcServiceClient(channel);
//var userInfo = returnModel.Data.BasicInfo;
//var tokenResponse = grpcClient.GetUserToken(new GetTokenReuqest()
//{
// Id = userInfo.Id.ToString(),
// ReviewerCode = userInfo.ReviewerCode,
// IsAdmin = userInfo.IsAdmin,
// RealName = userInfo.RealName,
// UserTypeEnumInt = (int)userInfo.UserTypeEnum,
// UserTypeShortName = userInfo.UserTypeShortName,
// UserName = userInfo.UserName
//});
//returnModel.Data.JWTStr = tokenResponse.Token;
#endregion
var userId = returnModel . Data . BasicInfo . Id ;
if ( _verifyConfig . CurrentValue . OpenLoginMFA )
{
//发版屏蔽
returnModel . Data . JWTStr = _tokenService . GetToken ( IRaCISClaims . Create ( returnModel . Data . BasicInfo ) ) ;
//MFA 发送邮件
returnModel . Data . IsMFA = true ;
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
returnModel . Data . BasicInfo . EMail = hiddenEmail ;
await _userService . SendMFAEmail ( userId ) ;
}
else
{
returnModel . Data . JWTStr = _tokenService . GetToken ( IRaCISClaims . Create ( returnModel . Data . BasicInfo ) ) ;
// 创建一个 CookieOptions 对象,用于设置 Cookie 的属性
var option = new CookieOptions
{
Expires = DateTime . Now . AddMonths ( 1 ) , // 设置过期时间为 30 分钟之后
HttpOnly = false , // 确保 cookie 只能通过 HTTP 访问
SameSite = Microsoft . AspNetCore . Http . SameSiteMode . None , // 设置 SameSite 属性
Secure = false // 确保 cookie 只能通过 HTTPS 访问
} ;
HttpContext . Response . Cookies . Append ( "access_token" , returnModel . Data . JWTStr , option ) ;
// 验证阅片休息时间
await readingImageTaskService . ResetReadingRestTime ( returnModel . Data . BasicInfo . Id ) ;
await provider . SetAsync ( userId . ToString ( ) , returnModel . Data . JWTStr , TimeSpan . FromDays ( 7 ) ) ;
await provider . SetAsync ( $"{userId.ToString()}_Online" , DateTime . Now . ToString ( "yyyy-MM-dd HH:mm:ss" ) , TimeSpan . FromMinutes ( _verifyConfig . CurrentValue . AutoLoginOutMinutes ) ) ;
}
}
return returnModel ;
}
var userId = returnModel . Data . BasicInfo . Id . ToString ( ) ;
//provider.Set(userId, userId, TimeSpan.FromMinutes(AppSettings.LoginExpiredTimeSpan));
// 验证阅片休息时间
await readingImageTaskService . ResetReadingRestTime ( returnModel . Data . BasicInfo . Id ) ;
await provider . SetAsync ( userId . ToString ( ) , returnModel . Data . JWTStr , TimeSpan . FromDays ( 7 ) ) ;
return returnModel ;
}
[HttpGet, Route("imageShare/ShareImage")]
[AllowAnonymous]
public IResponseOutput ShareImage ( [ FromServices ] ITokenService _tokenService )
@@ -223,7 +316,7 @@ namespace IRaCIS.Api.Controllers
var ossOptions = serviceOption . AliyunOSS ;
return ResponseOutput . Ok ( new ObjectStoreDTO ( ) { ObjectStoreUse = serviceOption . ObjectStoreUse , MinIO = serviceOption . MinIO , AliyunOSS = serviceOption . AliyunOSS , AWS = serviceOption . AWS } ) ;
return ResponseOutput . Ok ( new ObjectStoreDTO ( ) { ObjectStoreUse = serviceOption . ObjectStoreUse , MinIO = serviceOption . MinIO , AliyunOSS = serviceOption . AliyunOSS , AWS = serviceOption . AWS } ) ;
#region 临 时 token 屏 蔽
//IClientProfile profile = DefaultProfile.GetProfile(ossOptions.RegionId, ossOptions.AccessKeyId, ossOptions.AccessKeySecret);
@@ -264,19 +357,19 @@ namespace IRaCIS.Api.Controllers
#endregion
}
else if ( Enum . TryParse < ObjectStoreUse > ( serviceOption . ObjectStoreUse , out var parsedValue ) & & parsedValue = = ObjectStoreUse . MinIO )
else if ( Enum . TryParse < ObjectStoreUse > ( serviceOption . ObjectStoreUse , out var parsedValue ) & & parsedValue = = ObjectStoreUse . MinIO )
{
return ResponseOutput . Ok ( new ObjectStoreDTO ( ) { ObjectStoreUse = serviceOption . ObjectStoreUse , MinIO = serviceOption . MinIO , AWS = serviceOption . AWS } ) ;
return ResponseOutput . Ok ( new ObjectStoreDTO ( ) { ObjectStoreUse = serviceOption . ObjectStoreUse , MinIO = serviceOption . MinIO , AWS = serviceOption . AWS } ) ;
}
else
{
return ResponseOutput . Ok ( new ObjectStoreDTO ( ) { ObjectStoreUse = serviceOption . ObjectStoreUse , MinIO = serviceOption . MinIO , AWS = serviceOption . AWS } ) ;
}
}
[HttpGet("user/GenerateSTS")]
public IResponseOutput GenerateSTS ( [ FromServices ] IOptionsMonitor < AliyunOSSOptions > options )
[HttpGet("user/GenerateSTS")]
public IResponseOutput GenerateSTS ( [ FromServices ] IOptionsMonitor < AliyunOSSOptions > options )
{
var ossOptions = options . CurrentValue ;
@@ -304,9 +397,9 @@ namespace IRaCIS.Api.Controllers
SecurityToken = response . Credentials . SecurityToken ,
Expiration = response . Credentials . Expiration ,
Region = ossOptions . region ,
BucketName = ossOptions . bucketName ,
ViewEndpoint = ossOptions . viewEndpoint ,
Region = ossOptions . region ,
BucketName = ossOptions . bucketName ,
ViewEndpoint = ossOptions . viewEndpoint ,
} ;
@@ -318,12 +411,12 @@ namespace IRaCIS.Api.Controllers
[HttpGet("User/UserRedirect")]
[AllowAnonymous]
public async Task < IActionResult > UserRedirect ( [ FromServices ] IRepository < User > _userRepository , string url , [ FromServices ] ILogger < ExtraController > _logger )
public async Task < IActionResult > UserRedirect ( [ FromServices ] IRepository < User > _userRepository , string url , [ FromServices ] ILogger < ExtraController > _logger )
{
var decodeUrl = System . Web . HttpUtility . UrlDecode ( url ) ;
var userId = decodeUrl . Substring ( decodeUrl . IndexOf ( "UserId=" ) + "UserId=" . Length , 36 ) ;
var userId = decodeUrl . Substring ( decodeUrl . IndexOf ( "UserId=" ) + "UserId=" . Length , 36 ) ;
var token = decodeUrl . Substring ( decodeUrl . IndexOf ( "access_token=" ) + "access_token=" . Length ) ;
@@ -331,12 +424,12 @@ namespace IRaCIS.Api.Controllers
var domainStrList = decodeUrl . Split ( "/" ) . ToList ( ) . Take ( 3 ) . ToList ( ) ;
var errorUrl = domainStrList [ 0 ] + "//" + domainStrList [ 2 ] + "/error" ;
var errorUrl = domainStrList [ 0 ] + "//" + domainStrList [ 2 ] + "/error" ;
if ( ! await _userRepository . AnyAsync ( t = > t . Id = = Guid . Parse ( userId ) & & t . EmailToken = = token & & t . IsFirstAdd ) )
if ( ! await _userRepository . AnyAsync ( t = > t . Id = = Guid . Parse ( userId ) & & t . EmailToken = = token & & t . IsFirstAdd ) )
{
decodeUrl = errorUrl + $"?lang={lang}&ErrorMessage={System.Web.HttpUtility.UrlEncode(lang==" zh "? " 您 的 初 始 化 链 接 已 过 期 ": " Error ! The initialization link has expired . Return ")} " ;
decodeUrl = errorUrl + $"?lang={lang}&ErrorMessage={System.Web.HttpUtility.UrlEncode(lang == " zh " ? " 您 的 初 始 化 链 接 已 过 期 " : " Error ! The initialization link has expired . Return ")} " ;
}
return Redirect ( decodeUrl ) ;