using Amazon.Auth.AccessControlPolicy; using Amazon.SecurityToken; using AutoMapper; using Azure.Core; using IdentityModel.Client; using IdentityModel.OidcClient; using IRaCIS.Application.Contracts; using IRaCIS.Application.Interfaces; using IRaCIS.Core.Application.Auth; using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Helper; using IRaCIS.Core.Application.Service; using IRaCIS.Core.Domain.Models; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infra.EFCore; using IRaCIS.Core.Infrastructure.Extention; using MassTransit; using MassTransit.Futures.Contracts; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using RestSharp; using RestSharp.Authenticators; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; using System.Text; using System.Text.Json; using System.Threading.Tasks; using ZiggyCreatures.Caching.Fusion; using AssumeRoleRequest = Amazon.SecurityToken.Model.AssumeRoleRequest; using LoginReturnDTO = IRaCIS.Application.Contracts.LoginReturnDTO; namespace IRaCIS.Api.Controllers { /// /// 医生基本信息 、工作信息 专业信息、审核状态 /// [ApiController, ApiExplorerSettings(GroupName = "Reviewer")] public class ExtraController([FromServices] IAttachmentService attachmentService, [FromServices] IDoctorService _doctorService, [FromServices] IEducationService _educationService, [FromServices] ITrialExperienceService _trialExperienceService, [FromServices] IResearchPublicationService _researchPublicationService, [FromServices] IVacationService _vacationService) : ControllerBase { /// /// 获取医生详情 /// /// /// /// /// /// /// /// /// [HttpPost, Route("doctor/getDetail")] public async Task> GetDoctorDetail(GetDoctorDetailInDto inDto) { var education = await _educationService.GetEducation(inDto.doctorId); var sowList = _doctorService.GetDoctorSowList(inDto.doctorId); var ackSowList = _doctorService.GetDoctorAckSowList(inDto.doctorId); var doctorDetail = new DoctorDetailDTO { AuditView = await _doctorService.GetAuditState(inDto.doctorId), BasicInfoView = await _doctorService.GetBasicInfo(inDto.doctorId), EmploymentView = await _doctorService.GetEmploymentInfo(inDto.doctorId), AttachmentList = await attachmentService.GetAttachments(inDto.doctorId), SummarizeInfo = await _doctorService.GetSummarizeInfo(new GetSummarizeInfoInDto() { DoctorId = inDto.doctorId, TrialId = inDto.TrialId }), PaymentModeInfo = await _doctorService.GetPaymentMode(inDto.doctorId), EducationList = education.EducationList, PostgraduateList = education.PostgraduateList, TrialExperienceView = await _trialExperienceService.GetTrialExperience(new TrialExperienceModelIndto() { DoctorId = inDto.doctorId, TrialId = inDto.TrialId }), ResearchPublicationView = await _researchPublicationService.GetResearchPublication(inDto.doctorId), SpecialtyView = await _doctorService.GetSpecialtyInfo(inDto.doctorId), InHoliday = (await _vacationService.OnVacation(inDto.doctorId)).IsSuccess, IntoGroupInfo = _doctorService.GetDoctorIntoGroupInfo(inDto.doctorId), SowList = sowList, AckSowList = ackSowList }; return ResponseOutput.Ok(doctorDetail); } [AllowAnonymous] [HttpGet, Route("user/getPublicKey")] public IResponseOutput GetPublicKey([FromServices] IOptionsMonitor _IRCEncreptOption) { //var pemPublicKey = Encoding.UTF8.GetString(Convert.FromBase64String(_IRCEncreptOption.CurrentValue.Base64RSAPublicKey)); return ResponseOutput.Ok(_IRCEncreptOption.CurrentValue.Base64RSAPublicKey); } [HttpGet, Route("imageShare/ShareImage")] [AllowAnonymous] public IResponseOutput ShareImage([FromServices] ITokenService _tokenService) { var token = _tokenService.GetToken(new UserTokenInfo() { IdentityUserId = Guid.NewGuid(), UserName = "Share001", UserTypeEnum = UserTypeEnum.ShareImage, }); return ResponseOutput.Ok("/showdicom?studyId=f7b67793-8155-0223-2f15-118f2642efb8&type=Share&token=" + token); } [HttpGet("user/GetObjectStoreToken")] public async Task GetObjectStoreTokenAsync([FromServices] IOptionsMonitor options, [FromServices] IOSSService _oSSService) { var result = _oSSService.GetObjectStoreTempToken(); //result.AWS = await GetAWSTemToken(options.CurrentValue); return ResponseOutput.Ok(result); } private async Task GetAWSTemToken(ObjectStoreServiceOptions serviceOption) { var awsOptions = serviceOption.AWS; //aws 临时凭证 // 创建 STS 客户端 var stsClient = new AmazonSecurityTokenServiceClient(awsOptions.AccessKeyId, awsOptions.SecretAccessKey); // 使用 AssumeRole 请求临时凭证 var assumeRoleRequest = new AssumeRoleRequest { RoleArn = awsOptions.RoleArn, // 角色 ARN RoleSessionName = $"session-name-{NewId.NextGuid()}", DurationSeconds = awsOptions.DurationSeconds // 临时凭证有效期 }; var assumeRoleResponse = await stsClient.AssumeRoleAsync(assumeRoleRequest); var credentials = assumeRoleResponse.Credentials; var tempToken = new AWSTempToken() { AccessKeyId = credentials.AccessKeyId, SecretAccessKey = credentials.SecretAccessKey, SessionToken = credentials.SessionToken, Expiration = credentials.Expiration, Region = awsOptions.Region, BucketName = awsOptions.BucketName, EndPoint = awsOptions.EndPoint, ViewEndpoint = awsOptions.ViewEndpoint, }; return tempToken; } [HttpGet("User/UserRedirect")] [AllowAnonymous] public async Task UserRedirect([FromServices] IRepository _useRepository, string url, [FromServices] ILogger _logger, [FromServices] ITokenService _tokenService) { var decodeUrl = System.Web.HttpUtility.UrlDecode(url); var userId = decodeUrl.Substring(decodeUrl.IndexOf("UserId=") + "UserId=".Length, 36); var token = decodeUrl.Substring(decodeUrl.IndexOf("access_token=") + "access_token=".Length); var lang = decodeUrl.Substring(decodeUrl.IndexOf("lang=") + "lang=".Length, 2); var domainStrList = decodeUrl.Split("/").ToList().Take(3).ToList(); var errorUrl = domainStrList[0] + "//" + domainStrList[2] + "/error"; if (lang == "zh") { CultureInfo.CurrentCulture = new CultureInfo(StaticData.CultureInfo.zh_CN); CultureInfo.CurrentUICulture = new CultureInfo(StaticData.CultureInfo.zh_CN); } else { CultureInfo.CurrentCulture = new CultureInfo(StaticData.CultureInfo.en_US); CultureInfo.CurrentUICulture = new CultureInfo(StaticData.CultureInfo.en_US); } var isExpire = _tokenService.IsTokenExpired(token); if (!await _useRepository.AnyAsync(t => t.Id == Guid.Parse(userId) && t.EmailToken == token && t.IsFirstAdd) || isExpire) { decodeUrl = errorUrl + $"?lang={lang}&ErrorMessage={System.Web.HttpUtility.UrlEncode(I18n.T("UserRedirect_InitializationLinkExpire"))} "; } return Redirect(decodeUrl); } #region 项目支持Oauth 对接修改 /// /// 回调到前端,前端调用后端的接口 /// 参考链接:https://www.ruanyifeng.com/blog/2019/04/oauth-grant-types.html /// 后端通过这个code ,带上客户端信息,和授权类型 可以向单点登录提供商,获取厂商token /// /// 但是单点登录提供商提供的token 和我们系统的token 是有区别的,我们的token里面有我们业务系统的UserId,涉及到很多业务操作,所以在此出现了两种方案 /// 1、前端使用厂商的Token。 后端通过code 获取厂商的Token 返回前端的同时返回我们系统的UserId,前段在http 请求头加上一个自定义参数,带上UserId 后端取用户Id的地方变动下, /// 但是除了UserId外,后端还有其他信息也是从Token取的,所以在请求头也需要带上,此外后端认证Token的方式也需要变化,改造成本稍大(如果是微服务,做这种处理还是可以的)。 /// 2、前端还是使用我们后台自己的Token。后端通过code 获取厂商Token的同时,后端做一个隐藏登录,返回厂商的Token的同时,也返回我们系统的Token。 /// (像我们单体,这种方式最简单,我们用单点登录,无非就是不想记多个系统的密码,自动登录而已,其他不支持的项目改造成本也是最低的) /// /// 回调的厂商类型 比如github, google, 我们用的logto ,不同的厂商回调到前端的地址可以不同的,但是请求后端的接口可以是同一个 /// 在第三方平台登录成功后,回调前端的时候会返回一个code /// [HttpGet("User/OAuthCallBack")] public async Task OAuthCallBack(string type, string code) { #region 获取AccessTo //var headerDic = new Dictionary(); //headerDic.Add("code", code); //headerDic.Add("grant_type", "authorization_code"); //headerDic.Add("redirect_uri", "http://localhost:6100"); //headerDic.Add("scope", "all"); #endregion return ResponseOutput.Ok(); } #endregion #region 测试获取用户 ip [HttpGet, Route("ip")] [AllowAnonymous] public IResponseOutput Get([FromServices] IHttpContextAccessor _context) { StringBuilder sb = new StringBuilder(); sb.AppendLine($"RemoteIpAddress:{_context.HttpContext.Connection.RemoteIpAddress}"); if (Request.Headers.ContainsKey("X-Real-IP")) { sb.AppendLine($"X-Real-IP:{Request.Headers["X-Real-IP"].ToString()}"); } if (Request.Headers.ContainsKey("X-Forwarded-For")) { sb.AppendLine($"X-Forwarded-For:{Request.Headers["X-Forwarded-For"].ToString()}"); } return ResponseOutput.Ok(sb.ToString()); } [HttpGet, Route("ip2")] [AllowAnonymous] public IResponseOutput Get2([FromServices] IHttpContextAccessor _context) { StringBuilder sb = new StringBuilder(); sb.AppendLine($"RemoteIpAddress:{_context.HttpContext.Connection.RemoteIpAddress}"); if (Request.Headers.ContainsKey("X-Real-IP")) { sb.AppendLine($"X-Real-IP:{Request.Headers["X-Real-IP"].ToString()}"); } if (Request.Headers.ContainsKey("X-Forwarded-For")) { sb.AppendLine($"X-Forwarded-For:{Request.Headers["X-Forwarded-For"].ToString()}"); } return ResponseOutput.Ok(sb.ToString()); } #endregion } }