Compare commits
1 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
fa7c74dd21 | 1 week ago |
20 changed files with 861 additions and 988 deletions
@ -1,13 +0,0 @@ |
|||||||
{ |
|
||||||
"version": 1, |
|
||||||
"isRoot": true, |
|
||||||
"tools": { |
|
||||||
"dotnet-ef": { |
|
||||||
"version": "10.0.11", |
|
||||||
"commands": [ |
|
||||||
"dotnet-ef" |
|
||||||
], |
|
||||||
"rollForward": false |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,230 @@ |
|||||||
|
using CA_Platform_Linker.Models.Coss; |
||||||
|
using CA_Platform_Linker.Models.DTO; |
||||||
|
using CA_Platform_Linker.Services.Interfaces; |
||||||
|
using CA_Platform_Linker.Tools; |
||||||
|
using Microsoft.AspNetCore.Mvc; |
||||||
|
using System; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace CA_Platform_Linker.Controllers |
||||||
|
{ |
||||||
|
[Route("[controller]/[action]")]
|
||||||
|
[ApiController] |
||||||
|
public class ClientController : ControllerBase |
||||||
|
{ |
||||||
|
private readonly IClientService _clientService; |
||||||
|
|
||||||
|
public ClientController(IClientService clientService) |
||||||
|
{ |
||||||
|
_clientService = clientService; |
||||||
|
} |
||||||
|
|
||||||
|
[HttpPost] |
||||||
|
public async Task<IActionResult> Login([FromQuery] string clientType = "LIS") |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
|
||||||
|
var result = await _clientService.StartAutoSignAsync(clientType, 3600 * 24); |
||||||
|
LogHelper.Log.Info(result.ToString()); |
||||||
|
if (result.status == "200") |
||||||
|
{ |
||||||
|
return Ok(new ApiLoginResponse |
||||||
|
{ |
||||||
|
Success = true, |
||||||
|
Message = "二维码生成成功,请扫码登录", |
||||||
|
SignDataId = result.data.signDataId, |
||||||
|
QrCode = result.data.qrCode |
||||||
|
}); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
return BadRequest(new ApiLoginResponse |
||||||
|
{ |
||||||
|
Success = false, |
||||||
|
Message = $"二维码生成失败: {result.message}" |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
LogHelper.Log.Error($"二维码生成失败: {ex.Message}"); |
||||||
|
return BadRequest(new ApiLoginResponse |
||||||
|
{ |
||||||
|
Success = false, |
||||||
|
Message = $"二维码生成失败: {ex.Message}" |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[HttpPost] |
||||||
|
public async Task<IActionResult> AddSignJob([FromBody] ApiSignRequest request, [FromQuery] string clientType = "LIS") |
||||||
|
{ |
||||||
|
return BadRequest(new ApiSignResponse |
||||||
|
{ |
||||||
|
Success = false, |
||||||
|
Message = "接口已停用,请使用 AutoSign 接口" |
||||||
|
}); |
||||||
|
|
||||||
|
try |
||||||
|
{ |
||||||
|
var result = await _clientService.AddSignJobAsync( |
||||||
|
clientType, |
||||||
|
request.Title, |
||||||
|
request.Data, |
||||||
|
request.UserId, |
||||||
|
request.Algo, |
||||||
|
request.ExpiryDate |
||||||
|
); |
||||||
|
|
||||||
|
if (result.status == "200") |
||||||
|
{ |
||||||
|
return Ok(new ApiSignResponse |
||||||
|
{ |
||||||
|
Success = true, |
||||||
|
Message = "添加签名任务成功", |
||||||
|
SignDataId = result.data.signDataId, |
||||||
|
QrCode = result.data.qrCode |
||||||
|
}); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
return BadRequest(new ApiSignResponse |
||||||
|
{ |
||||||
|
Success = false, |
||||||
|
Message = $"添加签名任务失败: {result.message}" |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
LogHelper.Log.Error($"添加签名任务失败: {ex.Message}"); |
||||||
|
return BadRequest(new ApiSignResponse |
||||||
|
{ |
||||||
|
Success = false, |
||||||
|
Message = $"添加签名任务失败: {ex.Message}" |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[HttpPost] |
||||||
|
public async Task<IActionResult> AutoSign([FromBody] ApiAutoSignRequest request, [FromQuery] string clientType = "LIS", [FromQuery] int clientOper = 0) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
if (clientOper < 0 || clientOper > 99) |
||||||
|
{ |
||||||
|
return BadRequest(new ApiAutoSignResponse |
||||||
|
{ |
||||||
|
Success = false, |
||||||
|
Message = "clientOper 参数值必须在 0-99 范围内" |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
var result = await _clientService.AutoSignAsync( |
||||||
|
clientType, |
||||||
|
request.UserId, |
||||||
|
request.SignToken, |
||||||
|
request.Data, |
||||||
|
request.Algo, |
||||||
|
request.ExpiryDate, |
||||||
|
request.MZNum, |
||||||
|
request.ZYNum, |
||||||
|
request.SignID, |
||||||
|
clientOper |
||||||
|
); |
||||||
|
|
||||||
|
if (result.status == "200") |
||||||
|
{ |
||||||
|
return Ok(new ApiAutoSignResponse |
||||||
|
{ |
||||||
|
Success = true, |
||||||
|
Message = "自动签名成功", |
||||||
|
SignResult = result.data.signResult, |
||||||
|
SignCert = result.data.signCert, |
||||||
|
SignDataId = result.data.signDataId |
||||||
|
}); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
LogHelper.Log.Error($"自动签名失败: {result.message}"); |
||||||
|
return BadRequest(new ApiAutoSignResponse |
||||||
|
{ |
||||||
|
Success = false, |
||||||
|
Message = $"自动签名失败: {result.message}" |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
LogHelper.Log.Error($"自动签名失败: {ex.Message}"); |
||||||
|
return BadRequest(new ApiAutoSignResponse |
||||||
|
{ |
||||||
|
Success = false, |
||||||
|
Message = $"自动签名失败: {ex.Message}" |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[HttpPost] |
||||||
|
public async Task<IActionResult> GetSignResult([FromBody] ApiGetSignResultRequest request, [FromQuery] string clientType = "LIS") |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
var result = await _clientService.GetSignResultAsync(clientType, request.SignDataId); |
||||||
|
|
||||||
|
if (result.status == "200") |
||||||
|
{ |
||||||
|
string message = "查询中"; |
||||||
|
bool isLoginSuccess = false; |
||||||
|
|
||||||
|
if (result.data.jobStatus == "FINISH") |
||||||
|
{ |
||||||
|
message = "登录成功"; |
||||||
|
isLoginSuccess = true; |
||||||
|
} |
||||||
|
else if (result.data.jobStatus == "PROCESSING") |
||||||
|
{ |
||||||
|
message = "等待扫码"; |
||||||
|
} |
||||||
|
else if (result.data.jobStatus == "FAIL") |
||||||
|
{ |
||||||
|
message = "签名失败"; |
||||||
|
} |
||||||
|
else if (result.data.jobStatus == "TIMEOUT") |
||||||
|
{ |
||||||
|
message = "登录超时"; |
||||||
|
} |
||||||
|
|
||||||
|
return Ok(new ApiGetSignResultResponse |
||||||
|
{ |
||||||
|
Success = true, |
||||||
|
Message = message, |
||||||
|
JobStatus = result.data.jobStatus, |
||||||
|
SignResult = result.data.signResult, |
||||||
|
SignCert = result.data.signCert, |
||||||
|
UserId = result.data.msspId, |
||||||
|
IsLoginSuccess = isLoginSuccess |
||||||
|
}); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
return BadRequest(new ApiGetSignResultResponse |
||||||
|
{ |
||||||
|
Success = false, |
||||||
|
Message = $"获取签名结果失败: {result.message}" |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
LogHelper.Log.Error($"获取签名结果失败: {ex.Message}"); |
||||||
|
return BadRequest(new ApiGetSignResultResponse |
||||||
|
{ |
||||||
|
Success = false, |
||||||
|
Message = $"获取签名结果失败: {ex.Message}" |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -1,173 +0,0 @@ |
|||||||
using CA_Platform_Linker.Models.DTO; |
|
||||||
using CA_Platform_Linker.Services.Interfaces; |
|
||||||
using CA_Platform_Linker.Tools; |
|
||||||
using Microsoft.AspNetCore.Mvc; |
|
||||||
using System; |
|
||||||
using System.Threading.Tasks; |
|
||||||
|
|
||||||
namespace CA_Platform_Linker.Controllers |
|
||||||
{ |
|
||||||
[Route("[controller]/[action]")]
|
|
||||||
[ApiController] |
|
||||||
public class OnlineHospitalController : ControllerBase |
|
||||||
{ |
|
||||||
private readonly IOnlineHospitalService _onlineHospitalService; |
|
||||||
|
|
||||||
public OnlineHospitalController(IOnlineHospitalService onlineHospitalService) |
|
||||||
{ |
|
||||||
_onlineHospitalService = onlineHospitalService; |
|
||||||
} |
|
||||||
|
|
||||||
// SDK初始化已改为程序启动后自动执行(Startup中启动后台任务,每30秒循环调用init),不再对外暴露 |
|
||||||
//[HttpGet] |
|
||||||
//public async Task<IActionResult> InitSDK() |
|
||||||
//{ |
|
||||||
// try |
|
||||||
// { |
|
||||||
// var result = await _onlineHospitalService.InitSDKAsync(); |
|
||||||
// if (result.errCode == 0) |
|
||||||
// { |
|
||||||
// return Ok(ApiResponse.Ok(result.msg)); |
|
||||||
// } |
|
||||||
// LogHelper.Log.Error($"初始化SDK失败: {result.msg}"); |
|
||||||
// return Ok(ApiResponse.Fail(result.msg)); |
|
||||||
// } |
|
||||||
// catch (Exception ex) |
|
||||||
// { |
|
||||||
// LogHelper.Log.Error($"初始化SDK异常: {ex.Message}"); |
|
||||||
// return Ok(ApiResponse.Fail($"初始化SDK异常: {ex.Message}")); |
|
||||||
// } |
|
||||||
//} |
|
||||||
|
|
||||||
[HttpPost] |
|
||||||
public async Task<IActionResult> SignWithP7([FromBody] EsignSignRequest request) |
|
||||||
{ |
|
||||||
if (!SdkState.IsInitialized) |
|
||||||
{ |
|
||||||
return Ok(ApiResponse.Fail("SDK尚未初始化成功,请稍后重试")); |
|
||||||
} |
|
||||||
try |
|
||||||
{ |
|
||||||
if (string.IsNullOrEmpty(request.DoctorCode)) |
|
||||||
{ |
|
||||||
return Ok(ApiResponse.Fail("医生编号不能为空")); |
|
||||||
} |
|
||||||
if (string.IsNullOrEmpty(request.PlainText)) |
|
||||||
{ |
|
||||||
return Ok(ApiResponse.Fail("签名数据不能为空")); |
|
||||||
} |
|
||||||
|
|
||||||
var result = await _onlineHospitalService.SignWithP7Async(request.DoctorCode, request.PlainText); |
|
||||||
if (result.errCode == 0) |
|
||||||
{ |
|
||||||
var data = new |
|
||||||
{ |
|
||||||
signature = result.signature, |
|
||||||
algorithm = result.algorithm, |
|
||||||
signServiceId = result.signServiceId, |
|
||||||
certBean = result.certBean |
|
||||||
}; |
|
||||||
return Ok(ApiResponse.Ok(data, result.msg)); |
|
||||||
} |
|
||||||
LogHelper.Log.Error($"P7数据签名失败: {result.msg}"); |
|
||||||
return Ok(ApiResponse.Fail(result.msg)); |
|
||||||
} |
|
||||||
catch (Exception ex) |
|
||||||
{ |
|
||||||
LogHelper.Log.Error($"P7数据签名异常: {ex.Message}"); |
|
||||||
return Ok(ApiResponse.Fail($"P7数据签名异常: {ex.Message}")); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
[HttpPost] |
|
||||||
public async Task<IActionResult> VerifyP7([FromBody] EsignVerifyRequest request) |
|
||||||
{ |
|
||||||
if (!SdkState.IsInitialized) |
|
||||||
{ |
|
||||||
return Ok(ApiResponse.Fail("SDK尚未初始化成功,请稍后重试")); |
|
||||||
} |
|
||||||
try |
|
||||||
{ |
|
||||||
if (string.IsNullOrEmpty(request.PlainText)) |
|
||||||
{ |
|
||||||
return Ok(ApiResponse.Fail("签名原文不能为空")); |
|
||||||
} |
|
||||||
if (string.IsNullOrEmpty(request.Signature)) |
|
||||||
{ |
|
||||||
return Ok(ApiResponse.Fail("签名结果不能为空")); |
|
||||||
} |
|
||||||
|
|
||||||
var result = await _onlineHospitalService.VerifyP7Async(request.PlainText, request.Signature); |
|
||||||
if (result.errCode == 0) |
|
||||||
{ |
|
||||||
return Ok(ApiResponse.Ok(result.certBean, result.msg)); |
|
||||||
} |
|
||||||
LogHelper.Log.Error($"P7数据验签失败: {result.msg}"); |
|
||||||
return Ok(ApiResponse.Fail(result.msg)); |
|
||||||
} |
|
||||||
catch (Exception ex) |
|
||||||
{ |
|
||||||
LogHelper.Log.Error($"P7数据验签异常: {ex.Message}"); |
|
||||||
return Ok(ApiResponse.Fail($"P7数据验签异常: {ex.Message}")); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
[HttpPost] |
|
||||||
public async Task<IActionResult> CreatePersonAccount([FromBody] EsignCreatePersonRequest request) |
|
||||||
{ |
|
||||||
if (!SdkState.IsInitialized) |
|
||||||
{ |
|
||||||
return Ok(ApiResponse.Fail("SDK尚未初始化成功,请稍后重试")); |
|
||||||
} |
|
||||||
try |
|
||||||
{ |
|
||||||
if (string.IsNullOrEmpty(request.DoctorCode)) |
|
||||||
{ |
|
||||||
return Ok(ApiResponse.Fail("医生编号不能为空")); |
|
||||||
} |
|
||||||
|
|
||||||
var result = await _onlineHospitalService.CreatePersonAccountAsync(request.DoctorCode, request.flowId); |
|
||||||
if (result.errCode == 0) |
|
||||||
{ |
|
||||||
return Ok(ApiResponse.Ok(new { accountId = result.accountId }, result.msg)); |
|
||||||
} |
|
||||||
LogHelper.Log.Error($"创建个人签署账号失败: {result.msg}"); |
|
||||||
return Ok(ApiResponse.Fail(result.msg)); |
|
||||||
} |
|
||||||
catch (Exception ex) |
|
||||||
{ |
|
||||||
LogHelper.Log.Error($"创建个人签署账号异常: {ex.Message}"); |
|
||||||
return Ok(ApiResponse.Fail($"创建个人签署账号异常: {ex.Message}")); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
[HttpPost] |
|
||||||
public async Task<IActionResult> GetIndivAuthUrl([FromBody] EsignIndivAuthRequest request) |
|
||||||
{ |
|
||||||
if (!SdkState.IsInitialized) |
|
||||||
{ |
|
||||||
return Ok(ApiResponse.Fail("SDK尚未初始化成功,请稍后重试")); |
|
||||||
} |
|
||||||
try |
|
||||||
{ |
|
||||||
if (string.IsNullOrEmpty(request.DoctorCode)) |
|
||||||
{ |
|
||||||
return Ok(ApiResponse.Fail("医生编号不能为空")); |
|
||||||
} |
|
||||||
|
|
||||||
var result = await _onlineHospitalService.GetIndivAuthUrlAsync(request.DoctorCode); |
|
||||||
if (result.code == 0) |
|
||||||
{ |
|
||||||
return Ok(ApiResponse.Ok(result.data, result.message)); |
|
||||||
} |
|
||||||
LogHelper.Log.Error($"获取个人核身地址失败: {result.message}"); |
|
||||||
return Ok(ApiResponse.Fail(result.message)); |
|
||||||
} |
|
||||||
catch (Exception ex) |
|
||||||
{ |
|
||||||
LogHelper.Log.Error($"获取个人核身地址异常: {ex.Message}"); |
|
||||||
return Ok(ApiResponse.Fail($"获取个人核身地址异常: {ex.Message}")); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,96 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace CA_Platform_Linker.Models.Coss |
||||||
|
{ |
||||||
|
public class CossBaseRequest |
||||||
|
{ |
||||||
|
public string version { get; set; } |
||||||
|
public string appId { get; set; } |
||||||
|
public string signAlgo { get; set; } |
||||||
|
public string signature { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public class CossResponse<T> |
||||||
|
{ |
||||||
|
public string status { get; set; } |
||||||
|
public string message { get; set; } |
||||||
|
public T data { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public class CossResultData |
||||||
|
{ |
||||||
|
public string signDataId { get; set; } |
||||||
|
public string qrCode { get; set; } |
||||||
|
public string jobStatus { get; set; } |
||||||
|
public string msspId { get; set; } |
||||||
|
public string signCert { get; set; } |
||||||
|
public string signResult { get; set; } |
||||||
|
public string image { get; set; } |
||||||
|
public string tsResp { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public class StartAutoSignRequest : CossBaseRequest |
||||||
|
{ |
||||||
|
public string timeRegion { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public class AddSignJobRequest : CossBaseRequest |
||||||
|
{ |
||||||
|
public string title { get; set; } |
||||||
|
public string userId { get; set; } |
||||||
|
public string dataType { get; set; } |
||||||
|
public string algo { get; set; } |
||||||
|
public string description { get; set; } |
||||||
|
public string data { get; set; } |
||||||
|
public string expiryDate { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public class AutoSignRequest : CossBaseRequest |
||||||
|
{ |
||||||
|
public string userId { get; set; } |
||||||
|
public string title { get; set; } |
||||||
|
public string dataType { get; set; } |
||||||
|
public string algo { get; set; } |
||||||
|
public string description { get; set; } |
||||||
|
public string data { get; set; } |
||||||
|
public string signToken { get; set; } |
||||||
|
public string expiryDate { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public class GetSignResultRequest : CossBaseRequest |
||||||
|
{ |
||||||
|
public string signDataId { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public class QueryImageRequest : CossBaseRequest |
||||||
|
{ |
||||||
|
public string userId { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public class CreateTssRequest : CossBaseRequest |
||||||
|
{ |
||||||
|
public string oriData { get; set; } |
||||||
|
public string attachCert { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 验时间戳返回数据 |
||||||
|
/// </summary> |
||||||
|
public class CossVerifyResultData |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 验签结果:1=通过,-1=时间戳验证不通过,-2=原文验证不通过,-3=不是所信任的根,-4=证书未生效,-5=查询不到此证书,-6=服务器证书过期 |
||||||
|
/// </summary> |
||||||
|
public int verifyRes { get; set; } |
||||||
|
public string verifyMsg { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public class VerifyTssRequest : CossBaseRequest |
||||||
|
{ |
||||||
|
public string oriData { get; set; } |
||||||
|
public string tsResp { get; set; } |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,80 @@ |
|||||||
|
using System.ComponentModel.DataAnnotations; |
||||||
|
|
||||||
|
namespace CA_Platform_Linker.Models.DTO |
||||||
|
{ |
||||||
|
public class ApiLoginResponse |
||||||
|
{ |
||||||
|
public bool Success { get; set; } |
||||||
|
public string Message { get; set; } |
||||||
|
public string SignDataId { get; set; } |
||||||
|
public string QrCode { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public class ApiSignRequest |
||||||
|
{ |
||||||
|
[Required(ErrorMessage = "标题不能为空")] |
||||||
|
public string Title { get; set; } |
||||||
|
|
||||||
|
[Required(ErrorMessage = "数据不能为空")] |
||||||
|
public string Data { get; set; } |
||||||
|
|
||||||
|
public string UserId { get; set; } |
||||||
|
public string Algo { get; set; } = "SM3withSM2"; |
||||||
|
public string ExpiryDate { get; set; } = "1400"; |
||||||
|
} |
||||||
|
|
||||||
|
public class ApiSignResponse |
||||||
|
{ |
||||||
|
public bool Success { get; set; } |
||||||
|
public string Message { get; set; } |
||||||
|
public string SignDataId { get; set; } |
||||||
|
public string QrCode { get; set; } |
||||||
|
public string SignResult { get; set; } |
||||||
|
public string SignCert { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public class ApiAutoSignRequest |
||||||
|
{ |
||||||
|
[Required(ErrorMessage = "用户ID不能为空")] |
||||||
|
public string UserId { get; set; } |
||||||
|
|
||||||
|
[Required(ErrorMessage = "签名令牌不能为空")] |
||||||
|
public string SignToken { get; set; } |
||||||
|
|
||||||
|
[Required(ErrorMessage = "数据不能为空")] |
||||||
|
public string Data { get; set; } |
||||||
|
|
||||||
|
public string Algo { get; set; } = "SM3withSM2"; |
||||||
|
public string ExpiryDate { get; set; } = "1400"; |
||||||
|
|
||||||
|
public int MZNum { get; set; } = 0; |
||||||
|
public int ZYNum { get; set; } = 0; |
||||||
|
public string SignID { get; set; } = string.Empty; |
||||||
|
} |
||||||
|
|
||||||
|
public class ApiAutoSignResponse |
||||||
|
{ |
||||||
|
public bool Success { get; set; } |
||||||
|
public string Message { get; set; } |
||||||
|
public string SignResult { get; set; } |
||||||
|
public string SignCert { get; set; } |
||||||
|
public string SignDataId { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public class ApiGetSignResultRequest |
||||||
|
{ |
||||||
|
[Required(ErrorMessage = "签名数据ID不能为空")] |
||||||
|
public string SignDataId { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public class ApiGetSignResultResponse |
||||||
|
{ |
||||||
|
public bool Success { get; set; } |
||||||
|
public string Message { get; set; } |
||||||
|
public string JobStatus { get; set; } |
||||||
|
public string SignResult { get; set; } |
||||||
|
public string SignCert { get; set; } |
||||||
|
public string UserId { get; set; } |
||||||
|
public bool IsLoginSuccess { get; set; } |
||||||
|
} |
||||||
|
} |
||||||
@ -1,135 +0,0 @@ |
|||||||
using System.ComponentModel.DataAnnotations; |
|
||||||
|
|
||||||
namespace CA_Platform_Linker.Models.DTO |
|
||||||
{ |
|
||||||
/// <summary> |
|
||||||
/// 统一API响应模型 |
|
||||||
/// </summary> |
|
||||||
public class ApiResponse<T> |
|
||||||
{ |
|
||||||
public bool Success { get; set; } |
|
||||||
public string Message { get; set; } |
|
||||||
public T Data { get; set; } |
|
||||||
|
|
||||||
public static ApiResponse<T> Ok(T data, string message = "操作成功") |
|
||||||
=> new ApiResponse<T> { Success = true, Message = message, Data = data }; |
|
||||||
|
|
||||||
public static ApiResponse<T> Fail(string message) |
|
||||||
=> new ApiResponse<T> { Success = false, Message = message }; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary> |
|
||||||
/// 无数据负载的统一响应 |
|
||||||
/// </summary> |
|
||||||
public class ApiResponse : ApiResponse<object> |
|
||||||
{ |
|
||||||
public static ApiResponse Ok(string message = "操作成功") |
|
||||||
=> new ApiResponse { Success = true, Message = message }; |
|
||||||
|
|
||||||
public new static ApiResponse Fail(string message) |
|
||||||
=> new ApiResponse { Success = false, Message = message }; |
|
||||||
} |
|
||||||
|
|
||||||
public class EsignSdkResponse |
|
||||||
{ |
|
||||||
public int errCode { get; set; } |
|
||||||
public string msg { get; set; } |
|
||||||
public bool errShow { get; set; } |
|
||||||
} |
|
||||||
|
|
||||||
public class EsignSignRequest |
|
||||||
{ |
|
||||||
[Required(ErrorMessage = "医生编号不能为空")] |
|
||||||
public string DoctorCode { get; set; } |
|
||||||
|
|
||||||
[Required(ErrorMessage = "签名数据不能为空")] |
|
||||||
public string PlainText { get; set; } |
|
||||||
} |
|
||||||
|
|
||||||
public class EsignSdkSignResponse |
|
||||||
{ |
|
||||||
public int errCode { get; set; } |
|
||||||
public string msg { get; set; } |
|
||||||
public bool errShow { get; set; } |
|
||||||
public string signServiceId { get; set; } |
|
||||||
public string algorithm { get; set; } |
|
||||||
public string signature { get; set; } |
|
||||||
public EsignCertBean certBean { get; set; } |
|
||||||
} |
|
||||||
|
|
||||||
public class EsignCertBean |
|
||||||
{ |
|
||||||
public string sn { get; set; } |
|
||||||
public string cn { get; set; } |
|
||||||
public string ou { get; set; } |
|
||||||
public string issuerCN { get; set; } |
|
||||||
public string startDate { get; set; } |
|
||||||
public string endDate { get; set; } |
|
||||||
public string cert { get; set; } |
|
||||||
} |
|
||||||
|
|
||||||
public class EsignAccountQueryResponse |
|
||||||
{ |
|
||||||
public int errCode { get; set; } |
|
||||||
public string msg { get; set; } |
|
||||||
public bool errShow { get; set; } |
|
||||||
public string accountId { get; set; } |
|
||||||
public string name { get; set; } |
|
||||||
public string accountType { get; set; } |
|
||||||
public string idNo { get; set; } |
|
||||||
public string idNoType { get; set; } |
|
||||||
} |
|
||||||
|
|
||||||
public class EsignVerifyRequest |
|
||||||
{ |
|
||||||
[Required(ErrorMessage = "签名原文不能为空")] |
|
||||||
public string PlainText { get; set; } |
|
||||||
|
|
||||||
[Required(ErrorMessage = "签名结果不能为空")] |
|
||||||
public string Signature { get; set; } |
|
||||||
} |
|
||||||
|
|
||||||
public class EsignVerifyResponse |
|
||||||
{ |
|
||||||
public int errCode { get; set; } |
|
||||||
public string msg { get; set; } |
|
||||||
public bool errShow { get; set; } |
|
||||||
public EsignCertBean certBean { get; set; } |
|
||||||
} |
|
||||||
|
|
||||||
public class EsignCreatePersonRequest |
|
||||||
{ |
|
||||||
[Required(ErrorMessage = "医生编号不能为空")] |
|
||||||
public string DoctorCode { get; set; } |
|
||||||
|
|
||||||
public string flowId { get; set; } |
|
||||||
} |
|
||||||
|
|
||||||
public class EsignCreatePersonResponse |
|
||||||
{ |
|
||||||
public int errCode { get; set; } |
|
||||||
public string msg { get; set; } |
|
||||||
public bool errShow { get; set; } |
|
||||||
public string accountId { get; set; } |
|
||||||
} |
|
||||||
|
|
||||||
public class EsignIndivAuthRequest |
|
||||||
{ |
|
||||||
[Required(ErrorMessage = "医生编号不能为空")] |
|
||||||
public string DoctorCode { get; set; } |
|
||||||
} |
|
||||||
|
|
||||||
public class EsignIndivAuthResponse |
|
||||||
{ |
|
||||||
public int code { get; set; } |
|
||||||
public string message { get; set; } |
|
||||||
public EsignIndivAuthData data { get; set; } |
|
||||||
} |
|
||||||
|
|
||||||
public class EsignIndivAuthData |
|
||||||
{ |
|
||||||
public string flowId { get; set; } |
|
||||||
public string shortLink { get; set; } |
|
||||||
public string url { get; set; } |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,229 @@ |
|||||||
|
using CA_Platform_Linker.Models; |
||||||
|
using CA_Platform_Linker.Models.Coss; |
||||||
|
using CA_Platform_Linker.Services.Interfaces; |
||||||
|
using CA_Platform_Linker.Tools; |
||||||
|
using CA_Platform_Linker.Tools.Nlog; |
||||||
|
using System; |
||||||
|
using System.Collections; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace CA_Platform_Linker.Services |
||||||
|
{ |
||||||
|
public class ClientService : IClientService |
||||||
|
{ |
||||||
|
public async Task<CossResponse<CossResultData>> StartAutoSignAsync(string clientType, int timeRegion = 3600 * 24) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
Hashtable ht = CossHelper.BuildBaseHashtable(clientType); |
||||||
|
ht.Add("timeRegion", timeRegion.ToString()); |
||||||
|
return await CossHelper.PostAsync<CossResultData>("startAutoSign", ht, clientType); |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
LogHelper.Log.Error($"开启自动签名失败: {ex.Message}"); |
||||||
|
return new CossResponse<CossResultData> |
||||||
|
{ |
||||||
|
status = "500", |
||||||
|
message = ex.Message |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public async Task<CossResponse<CossResultData>> AddSignJobAsync(string clientType, string title, string data, string userId = "", string algo = "SM3withSM2", string expiryDate = "1400") |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
string base64Data = data; |
||||||
|
if (!string.IsNullOrEmpty(data)) |
||||||
|
{ |
||||||
|
base64Data = CossHelper.Base64Encode(data); |
||||||
|
} |
||||||
|
|
||||||
|
Hashtable ht = CossHelper.BuildBaseHashtable(clientType); |
||||||
|
ht.Add("title", title); |
||||||
|
ht.Add("dataType", "DATA"); |
||||||
|
ht.Add("algo", algo); |
||||||
|
ht.Add("description", clientType + "签名任务"); |
||||||
|
ht.Add("data", base64Data); |
||||||
|
ht.Add("expiryDate", expiryDate); |
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(userId)) |
||||||
|
{ |
||||||
|
ht.Add("userId", userId); |
||||||
|
} |
||||||
|
|
||||||
|
return await CossHelper.PostAsync<CossResultData>("addSignJob", ht, clientType); |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
LogHelper.Log.Error($"添加签名任务失败: {ex.Message}"); |
||||||
|
return new CossResponse<CossResultData> |
||||||
|
{ |
||||||
|
status = "500", |
||||||
|
message = ex.Message |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public async Task<CossResponse<CossResultData>> AutoSignAsync(string clientType, string userId, string signToken, string data, string algo = "SM3withSM2", string expiryDate = "1400", int mzNum = 0, int zyNum = 0, string signID = "", int clientOper = 0) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
string base64Data = data; |
||||||
|
if (!string.IsNullOrEmpty(data)) |
||||||
|
{ |
||||||
|
base64Data = CossHelper.Base64Encode(data); |
||||||
|
} |
||||||
|
|
||||||
|
Hashtable ht = CossHelper.BuildBaseHashtable(clientType); |
||||||
|
ht.Add("userId", userId); |
||||||
|
ht.Add("title", clientType + "自动签名"); |
||||||
|
ht.Add("dataType", "DATA"); |
||||||
|
ht.Add("algo", algo); |
||||||
|
ht.Add("description", clientType + "自动签名"); |
||||||
|
ht.Add("data", base64Data); |
||||||
|
ht.Add("signToken", signToken); |
||||||
|
ht.Add("expiryDate", expiryDate); |
||||||
|
|
||||||
|
var result = await CossHelper.PostAsync<CossResultData>("autoSign", ht, clientType); |
||||||
|
|
||||||
|
if (result.status == "200") |
||||||
|
{ |
||||||
|
_ = Task.Run(async () => |
||||||
|
{ |
||||||
|
string tsData = ""; |
||||||
|
try |
||||||
|
{ |
||||||
|
// 1. 协同加盖时间戳 |
||||||
|
var createTssRes = await CreateTssAsync(clientType, base64Data); |
||||||
|
if (createTssRes.status != "200" || string.IsNullOrEmpty(createTssRes.data?.tsResp)) |
||||||
|
{ |
||||||
|
string errMsg = $"加盖时间戳失败: {createTssRes.message ?? "tsResp为空"}"; |
||||||
|
LogHelper.Log.Error(errMsg); |
||||||
|
return; |
||||||
|
} |
||||||
|
tsData = createTssRes.data.tsResp; |
||||||
|
LogHelper.Log.Info($"加盖时间戳成功,SignDataId: {result.data.signDataId}"); |
||||||
|
|
||||||
|
// 2. 时间戳验签 |
||||||
|
var verifyTssRes = await VerifyTssAsync(clientType, base64Data, tsData); |
||||||
|
if (verifyTssRes.status != "200" || verifyTssRes.data?.verifyRes != 1) |
||||||
|
{ |
||||||
|
string errMsg = $"时间戳验签失败: {verifyTssRes.message ?? verifyTssRes.data?.verifyMsg ?? "未知错误"}"; |
||||||
|
LogHelper.Log.Error(errMsg); |
||||||
|
return; |
||||||
|
} |
||||||
|
LogHelper.Log.Info($"时间戳验签通过,SignDataId: {result.data.signDataId}"); |
||||||
|
|
||||||
|
// 3. 验签通过,写入数据库 |
||||||
|
var clientConfig = ConfigHelper.GetCossClientConfig(clientType); |
||||||
|
var (operCode, operName) = SqlHelper.GetOperatorInfo(userId); |
||||||
|
var signInfo = new SignInfo |
||||||
|
{ |
||||||
|
TextType = clientConfig.TextType + clientOper, |
||||||
|
MZNum = mzNum, |
||||||
|
ZYNum = zyNum, |
||||||
|
SourceText = data, |
||||||
|
Base64Text = "", |
||||||
|
OperCode = operCode ?? "", |
||||||
|
OperName = operName ?? "", |
||||||
|
SignDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), |
||||||
|
CertID = result.data.msspId ?? "", |
||||||
|
OperCert = result.data.signCert, |
||||||
|
SignData = result.data.signResult, |
||||||
|
TSData = tsData, |
||||||
|
SignID = signID, |
||||||
|
OperType = clientType + "自动签名", |
||||||
|
SignWay = 1 |
||||||
|
}; |
||||||
|
|
||||||
|
SqlHelper.InsertSignInfo(signInfo); |
||||||
|
LogHelper.Log.Info($"签名记录已写入数据库,SignDataId: {result.data.signDataId}"); |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
LogHelper.Log.Error($"签名后处理流程异常:{ex.Message}"); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
LogHelper.Log.Error($"自动签名失败: {ex.Message}"); |
||||||
|
return new CossResponse<CossResultData> |
||||||
|
{ |
||||||
|
status = "500", |
||||||
|
message = ex.Message |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public async Task<CossResponse<CossResultData>> GetSignResultAsync(string clientType, string signDataId) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
Hashtable ht = CossHelper.BuildBaseHashtable(clientType); |
||||||
|
ht.Add("signDataId", signDataId); |
||||||
|
return await CossHelper.PostAsync<CossResultData>("getSignResult", ht, clientType); |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
LogHelper.Log.Error($"获取签名结果失败: {ex.Message}"); |
||||||
|
return new CossResponse<CossResultData> |
||||||
|
{ |
||||||
|
status = "500", |
||||||
|
message = ex.Message |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 协同加盖时间戳(参考Demo: createAndGetTssInfo) |
||||||
|
/// </summary> |
||||||
|
public async Task<CossResponse<CossResultData>> CreateTssAsync(string clientType, string oriData) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
Hashtable ht = CossHelper.BuildBaseHashtable(clientType); |
||||||
|
ht.Add("oriData", oriData); |
||||||
|
ht.Add("attachCert", "true"); |
||||||
|
return await CossHelper.PostAsync<CossResultData>("createAndGetTssInfo", ht, clientType); |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
LogHelper.Log.Error($"加盖时间戳失败: {ex.Message}"); |
||||||
|
return new CossResponse<CossResultData> |
||||||
|
{ |
||||||
|
status = "500", |
||||||
|
message = ex.Message |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 时间戳验签(参考Demo: verifyTS) |
||||||
|
/// </summary> |
||||||
|
public async Task<CossResponse<CossVerifyResultData>> VerifyTssAsync(string clientType, string oriData, string tsResp) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
Hashtable ht = CossHelper.BuildBaseHashtable(clientType); |
||||||
|
ht.Add("oriData", oriData); |
||||||
|
ht.Add("tsResp", tsResp); |
||||||
|
return await CossHelper.PostAsync<CossVerifyResultData>("verifyTS", ht, clientType); |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
LogHelper.Log.Error($"时间戳验签失败: {ex.Message}"); |
||||||
|
return new CossResponse<CossVerifyResultData> |
||||||
|
{ |
||||||
|
status = "500", |
||||||
|
message = ex.Message |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
using CA_Platform_Linker.Models.Coss; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace CA_Platform_Linker.Services.Interfaces |
||||||
|
{ |
||||||
|
public interface IClientService |
||||||
|
{ |
||||||
|
Task<CossResponse<CossResultData>> StartAutoSignAsync(string clientType, int timeRegion = 3600 * 24); |
||||||
|
Task<CossResponse<CossResultData>> AddSignJobAsync(string clientType, string title, string data, string userId = "", string algo = "SM3withSM2", string expiryDate = "1400"); |
||||||
|
Task<CossResponse<CossResultData>> AutoSignAsync(string clientType, string userId, string signToken, string data, string algo = "SM3withSM2", string expiryDate = "1400", int mzNum = 0, int zyNum = 0, string signID = "", int clientOper = 0); |
||||||
|
Task<CossResponse<CossResultData>> GetSignResultAsync(string clientType, string signDataId); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 协同加盖时间戳(参考Demo: createAndGetTssInfo) |
||||||
|
/// </summary> |
||||||
|
Task<CossResponse<CossResultData>> CreateTssAsync(string clientType, string oriData); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 时间戳验签(参考Demo: verifyTS) |
||||||
|
/// </summary> |
||||||
|
Task<CossResponse<CossVerifyResultData>> VerifyTssAsync(string clientType, string oriData, string tsResp); |
||||||
|
} |
||||||
|
} |
||||||
@ -1,14 +0,0 @@ |
|||||||
using CA_Platform_Linker.Models.DTO; |
|
||||||
using System.Threading.Tasks; |
|
||||||
|
|
||||||
namespace CA_Platform_Linker.Services.Interfaces |
|
||||||
{ |
|
||||||
public interface IOnlineHospitalService |
|
||||||
{ |
|
||||||
Task<EsignSdkResponse> InitSDKAsync(); |
|
||||||
Task<EsignSdkSignResponse> SignWithP7Async(string doctorCode, string plainText); |
|
||||||
Task<EsignVerifyResponse> VerifyP7Async(string plainText, string signature); |
|
||||||
Task<EsignCreatePersonResponse> CreatePersonAccountAsync(string doctorCode, string flowId); |
|
||||||
Task<EsignIndivAuthResponse> GetIndivAuthUrlAsync(string doctorCode); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,318 +0,0 @@ |
|||||||
using CA_Platform_Linker.Models.DTO; |
|
||||||
using CA_Platform_Linker.Services.Interfaces; |
|
||||||
using CA_Platform_Linker.Tools; |
|
||||||
using Newtonsoft.Json; |
|
||||||
using System; |
|
||||||
using System.Net.Http; |
|
||||||
using System.Text; |
|
||||||
using System.Threading.Tasks; |
|
||||||
|
|
||||||
namespace CA_Platform_Linker.Services |
|
||||||
{ |
|
||||||
public class OnlineHospitalService : IOnlineHospitalService |
|
||||||
{ |
|
||||||
private static readonly HttpClient _httpClient = new HttpClient |
|
||||||
{ |
|
||||||
Timeout = TimeSpan.FromSeconds(15) |
|
||||||
}; |
|
||||||
|
|
||||||
private const string SdkInitPath = "/paas-sdk-service/timevale/init"; |
|
||||||
private const string SdkSignP7Path = "/paas-sdk-service/timevale/user/sign/localDigitalSignWithP7"; |
|
||||||
private const string SdkVerifyP7Path = "/paas-sdk-service/timevale/user/sign/digitalVerifyWithP7"; |
|
||||||
private const string SdkCreatePersonPath = "/paas-sdk-service/timevale/account/addPerson"; |
|
||||||
private const string OpenAuthUrlPath = "/v2/identity/auth/web/indivAuthUrl"; |
|
||||||
|
|
||||||
private static string BuildUrl(string path) => ConfigHelper.EsignSdkBaseUrl + path; |
|
||||||
|
|
||||||
private static async Task<string> PostJsonAsync(string url, object body, string logTag) |
|
||||||
{ |
|
||||||
string strJson = JsonConvert.SerializeObject(body); |
|
||||||
LogHelper.Log.Info($"{logTag} 请求: {url} | {strJson}"); |
|
||||||
|
|
||||||
using (var content = new StringContent(strJson, Encoding.UTF8, "application/json")) |
|
||||||
using (var response = await _httpClient.PostAsync(url, content)) |
|
||||||
{ |
|
||||||
string responseStr = await response.Content.ReadAsStringAsync(); |
|
||||||
LogHelper.Log.Info($"{logTag} 响应: {responseStr}"); |
|
||||||
return responseStr; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private static string FormatTimeoutMsg(string url, Exception ex) |
|
||||||
{ |
|
||||||
if (ex is TaskCanceledException || ex.InnerException is TaskCanceledException) |
|
||||||
{ |
|
||||||
return $"请求超时,e签宝SDK服务无响应,请检查 {ConfigHelper.EsignSdkBaseUrl} 是否启动且可访问"; |
|
||||||
} |
|
||||||
if (ex is HttpRequestException || ex.InnerException is HttpRequestException) |
|
||||||
{ |
|
||||||
return $"无法连接e签宝SDK服务 {ConfigHelper.EsignSdkBaseUrl},请确认服务已启动且网络可达: {ex.Message}"; |
|
||||||
} |
|
||||||
return ex.Message; |
|
||||||
} |
|
||||||
|
|
||||||
public async Task<EsignSdkResponse> InitSDKAsync() |
|
||||||
{ |
|
||||||
try |
|
||||||
{ |
|
||||||
var requestBody = new |
|
||||||
{ |
|
||||||
projectConfig = new |
|
||||||
{ |
|
||||||
projectId = ConfigHelper.EsignProjectId, |
|
||||||
projectSecret = ConfigHelper.EsignProjectSecret, |
|
||||||
itsmApiUrl = ConfigHelper.EsignItsmApiUrl |
|
||||||
}, |
|
||||||
httpConfig = new |
|
||||||
{ |
|
||||||
httpType = "HTTP", |
|
||||||
retry = 5 |
|
||||||
}, |
|
||||||
signConfig = new |
|
||||||
{ |
|
||||||
algorithm = "HMACSHA256" |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
string responseStr = await PostJsonAsync(BuildUrl(SdkInitPath), requestBody, "初始化SDK"); |
|
||||||
return JsonConvert.DeserializeObject<EsignSdkResponse>(responseStr); |
|
||||||
} |
|
||||||
catch (Exception ex) |
|
||||||
{ |
|
||||||
string msg = FormatTimeoutMsg(BuildUrl(SdkInitPath), ex); |
|
||||||
LogHelper.Log.Error($"初始化SDK失败: {msg}"); |
|
||||||
return new EsignSdkResponse |
|
||||||
{ |
|
||||||
errCode = 500, |
|
||||||
msg = msg |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public async Task<EsignSdkSignResponse> SignWithP7Async(string doctorCode, string plainText) |
|
||||||
{ |
|
||||||
try |
|
||||||
{ |
|
||||||
var (accountId, doctorName) = SqlHelper.GetCaAccountInfo(doctorCode); |
|
||||||
if (string.IsNullOrEmpty(accountId)) |
|
||||||
{ |
|
||||||
return new EsignSdkSignResponse |
|
||||||
{ |
|
||||||
errCode = 404, |
|
||||||
msg = $"未找到医生 {doctorCode} 的CA账号,请先创建签署账号" |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
var requestBody = new |
|
||||||
{ |
|
||||||
accountId = accountId, |
|
||||||
plainText = plainText |
|
||||||
}; |
|
||||||
|
|
||||||
string responseStr = await PostJsonAsync(BuildUrl(SdkSignP7Path), requestBody, "P7数据签名"); |
|
||||||
var result = JsonConvert.DeserializeObject<EsignSdkSignResponse>(responseStr); |
|
||||||
|
|
||||||
if (result.errCode == 0) |
|
||||||
{ |
|
||||||
try |
|
||||||
{ |
|
||||||
SqlHelper.SaveSignRecord( |
|
||||||
doctorCode, doctorName, accountId, plainText, |
|
||||||
result.signature, result.algorithm, result.signServiceId, |
|
||||||
result.certBean?.sn, result.certBean?.cn, result.certBean?.issuerCN, |
|
||||||
result.certBean?.startDate, result.certBean?.endDate); |
|
||||||
LogHelper.Log.Info($"签名记录已存档: {doctorCode}"); |
|
||||||
} |
|
||||||
catch (Exception dbEx) |
|
||||||
{ |
|
||||||
LogHelper.Log.Error($"签名记录存档失败: {dbEx.Message}"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return result; |
|
||||||
} |
|
||||||
catch (Exception ex) |
|
||||||
{ |
|
||||||
string msg = FormatTimeoutMsg(BuildUrl(SdkSignP7Path), ex); |
|
||||||
LogHelper.Log.Error($"P7数据签名失败: {msg}"); |
|
||||||
return new EsignSdkSignResponse |
|
||||||
{ |
|
||||||
errCode = 500, |
|
||||||
msg = msg |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public async Task<EsignVerifyResponse> VerifyP7Async(string plainText, string signature) |
|
||||||
{ |
|
||||||
try |
|
||||||
{ |
|
||||||
var requestBody = new |
|
||||||
{ |
|
||||||
plainText = plainText, |
|
||||||
signature = signature |
|
||||||
}; |
|
||||||
|
|
||||||
string responseStr = await PostJsonAsync(BuildUrl(SdkVerifyP7Path), requestBody, "P7数据验签"); |
|
||||||
return JsonConvert.DeserializeObject<EsignVerifyResponse>(responseStr); |
|
||||||
} |
|
||||||
catch (Exception ex) |
|
||||||
{ |
|
||||||
string msg = FormatTimeoutMsg(BuildUrl(SdkVerifyP7Path), ex); |
|
||||||
LogHelper.Log.Error($"P7数据验签失败: {msg}"); |
|
||||||
return new EsignVerifyResponse |
|
||||||
{ |
|
||||||
errCode = 500, |
|
||||||
msg = msg |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public async Task<EsignCreatePersonResponse> CreatePersonAccountAsync(string doctorCode, string flowId) |
|
||||||
{ |
|
||||||
try |
|
||||||
{ |
|
||||||
string name; |
|
||||||
string personId; |
|
||||||
|
|
||||||
if (doctorCode == "54333") |
|
||||||
{ |
|
||||||
name = "李嘉文"; |
|
||||||
personId = "230183199612120231"; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
var (n, p) = SqlHelper.GetDoctorInfo(doctorCode); |
|
||||||
name = n; |
|
||||||
personId = p; |
|
||||||
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(personId)) |
|
||||||
{ |
|
||||||
return new EsignCreatePersonResponse |
|
||||||
{ |
|
||||||
errCode = 404, |
|
||||||
msg = $"未找到医生 {doctorCode} 的信息,请确认医生编号正确" |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
var requestBody = new |
|
||||||
{ |
|
||||||
name = name, |
|
||||||
idNo = personId, |
|
||||||
idNoType = "MAINLAND", |
|
||||||
encrypt = false |
|
||||||
}; |
|
||||||
|
|
||||||
string responseStr = await PostJsonAsync(BuildUrl(SdkCreatePersonPath), requestBody, "创建个人签署账号"); |
|
||||||
var result = JsonConvert.DeserializeObject<EsignCreatePersonResponse>(responseStr); |
|
||||||
|
|
||||||
if (result.errCode == 0 && !string.IsNullOrEmpty(result.accountId)) |
|
||||||
{ |
|
||||||
SqlHelper.SaveCaAccountId(doctorCode, name, result.accountId); |
|
||||||
LogHelper.Log.Info($"保存CA账号映射成功: {doctorCode} -> {result.accountId}"); |
|
||||||
} |
|
||||||
|
|
||||||
return result; |
|
||||||
} |
|
||||||
catch (Exception ex) |
|
||||||
{ |
|
||||||
string msg = FormatTimeoutMsg(BuildUrl(SdkCreatePersonPath), ex); |
|
||||||
LogHelper.Log.Error($"创建个人签署账号失败: {msg}"); |
|
||||||
return new EsignCreatePersonResponse |
|
||||||
{ |
|
||||||
errCode = 500, |
|
||||||
msg = msg |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public async Task<EsignIndivAuthResponse> GetIndivAuthUrlAsync(string doctorCode) |
|
||||||
{ |
|
||||||
try |
|
||||||
{ |
|
||||||
string name; |
|
||||||
string personId; |
|
||||||
|
|
||||||
if (doctorCode == "54333") |
|
||||||
{ |
|
||||||
name = "李嘉文"; |
|
||||||
personId = "230183199612120231"; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
var (n, p) = SqlHelper.GetDoctorInfo(doctorCode); |
|
||||||
name = n; |
|
||||||
personId = p; |
|
||||||
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(personId)) |
|
||||||
{ |
|
||||||
return new EsignIndivAuthResponse |
|
||||||
{ |
|
||||||
code = 404, |
|
||||||
message = $"未找到医生 {doctorCode} 的信息,请确认医生编号正确" |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
var requestBody = new |
|
||||||
{ |
|
||||||
indivInfo = new |
|
||||||
{ |
|
||||||
name = name, |
|
||||||
certNo = personId, |
|
||||||
certType = "INDIVIDUAL_CH_IDCARD" |
|
||||||
}, |
|
||||||
configParams = new |
|
||||||
{ |
|
||||||
indivUneditableInfo = new[] { "name", "certNo", "certType" } |
|
||||||
}, |
|
||||||
contextInfo = new |
|
||||||
{ |
|
||||||
origin = "BROWSER", |
|
||||||
showResultPage = true |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
string url = ConfigHelper.EsignOpenApiBaseUrl + OpenAuthUrlPath; |
|
||||||
string strJson = JsonConvert.SerializeObject(requestBody); |
|
||||||
LogHelper.Log.Info($"获取个人核身地址请求: {url} | {strJson}"); |
|
||||||
|
|
||||||
// 先创建Content获取实际Content-Type值,确保签名与发送一致 |
|
||||||
var content = new StringContent(strJson, Encoding.UTF8, "application/json"); |
|
||||||
string actualContentType = content.Headers.ContentType.ToString(); |
|
||||||
|
|
||||||
// e签宝开放平台签名鉴权 |
|
||||||
var (signature, contentMD5, timestamp) = EsignSignatureHelper.BuildSignature( |
|
||||||
"POST", OpenAuthUrlPath, strJson, ConfigHelper.EsignProjectSecret, actualContentType); |
|
||||||
|
|
||||||
content.Headers.Add("Content-MD5", contentMD5); |
|
||||||
|
|
||||||
using (var request = new HttpRequestMessage(HttpMethod.Post, url)) |
|
||||||
{ |
|
||||||
request.Headers.Add("X-Tsign-Open-App-Id", ConfigHelper.EsignProjectId); |
|
||||||
request.Headers.Add("X-Tsign-Open-Auth-Mode", "Signature"); |
|
||||||
request.Headers.Add("X-Tsign-Open-Ca-Signature", signature); |
|
||||||
request.Headers.Add("X-Tsign-Open-Ca-Timestamp", timestamp); |
|
||||||
request.Headers.Add("Accept", "*/*"); |
|
||||||
request.Content = content; |
|
||||||
|
|
||||||
using (var response = await _httpClient.SendAsync(request)) |
|
||||||
{ |
|
||||||
string responseStr = await response.Content.ReadAsStringAsync(); |
|
||||||
LogHelper.Log.Info($"获取个人核身地址响应: {responseStr}"); |
|
||||||
return JsonConvert.DeserializeObject<EsignIndivAuthResponse>(responseStr); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
catch (Exception ex) |
|
||||||
{ |
|
||||||
string msg = FormatTimeoutMsg(ConfigHelper.EsignOpenApiBaseUrl + OpenAuthUrlPath, ex); |
|
||||||
LogHelper.Log.Error($"获取个人核身地址失败: {msg}"); |
|
||||||
return new EsignIndivAuthResponse |
|
||||||
{ |
|
||||||
code = 500, |
|
||||||
message = msg |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,93 @@ |
|||||||
|
using CA_Platform_Linker.Models.Coss; |
||||||
|
using CA_Platform_Linker.Tools; |
||||||
|
using CA_Platform_Linker.Tools.Nlog; |
||||||
|
using Newtonsoft.Json; |
||||||
|
using System; |
||||||
|
using System.Collections; |
||||||
|
using System.Linq; |
||||||
|
using System.Net.Http; |
||||||
|
using System.Security.Cryptography; |
||||||
|
using System.Text; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace CA_Platform_Linker.Tools |
||||||
|
{ |
||||||
|
public class CossHelper |
||||||
|
{ |
||||||
|
private static readonly HttpClient _httpClient = new HttpClient(); |
||||||
|
|
||||||
|
public static string GetSignature(string secret, string content) |
||||||
|
{ |
||||||
|
secret = secret ?? ""; |
||||||
|
var encoding = Encoding.UTF8; |
||||||
|
byte[] keyByte = encoding.GetBytes(secret); |
||||||
|
byte[] messageBytes = encoding.GetBytes(content); |
||||||
|
using (var hmacsha256 = new HMACSHA256(keyByte)) |
||||||
|
{ |
||||||
|
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes); |
||||||
|
return Convert.ToBase64String(hashmessage); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static string GetSignatureValue(Hashtable ht, string secureCode) |
||||||
|
{ |
||||||
|
string str = ""; |
||||||
|
ArrayList akeys = new ArrayList(ht.Keys); |
||||||
|
akeys.Sort(); |
||||||
|
foreach (string key in akeys) |
||||||
|
{ |
||||||
|
str += key + "=" + ht[key] + "&"; |
||||||
|
} |
||||||
|
str = str.Substring(0, str.Length - 1); |
||||||
|
return GetSignature(secureCode, str); |
||||||
|
} |
||||||
|
|
||||||
|
public static Hashtable BuildBaseHashtable(string clientType) |
||||||
|
{ |
||||||
|
var clientConfig = ConfigHelper.GetCossClientConfig(clientType); |
||||||
|
Hashtable ht = new Hashtable(); |
||||||
|
ht.Add("version", ConfigHelper.CossVersion); |
||||||
|
ht.Add("appId", clientConfig.AppId); |
||||||
|
ht.Add("signAlgo", ConfigHelper.CossSignAlgo); |
||||||
|
return ht; |
||||||
|
} |
||||||
|
|
||||||
|
public static async Task<CossResponse<T>> PostAsync<T>(string apiName, Hashtable ht, string clientType) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
var clientConfig = ConfigHelper.GetCossClientConfig(clientType); |
||||||
|
ht.Add("signature", GetSignatureValue(ht, clientConfig.SecureCode)); |
||||||
|
string strJson = JsonConvert.SerializeObject(ht); |
||||||
|
string url = ConfigHelper.CossBaseUrl + apiName; |
||||||
|
|
||||||
|
var content = new StringContent(strJson, Encoding.UTF8, "application/json"); |
||||||
|
var response = await _httpClient.PostAsync(url, content); |
||||||
|
string responseStr = await response.Content.ReadAsStringAsync(); |
||||||
|
|
||||||
|
return JsonConvert.DeserializeObject<CossResponse<T>>(responseStr); |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
LogHelper.Log.Error($"CA服务调用失败: {ex.Message}"); |
||||||
|
return new CossResponse<T> |
||||||
|
{ |
||||||
|
status = "500", |
||||||
|
message = ex.Message |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static string Base64Encode(string plainText) |
||||||
|
{ |
||||||
|
var plainTextBytes = Encoding.UTF8.GetBytes(plainText); |
||||||
|
return Convert.ToBase64String(plainTextBytes); |
||||||
|
} |
||||||
|
|
||||||
|
public static string Base64Decode(string base64EncodedData) |
||||||
|
{ |
||||||
|
var base64EncodedBytes = Convert.FromBase64String(base64EncodedData); |
||||||
|
return Encoding.UTF8.GetString(base64EncodedBytes); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -1,82 +0,0 @@ |
|||||||
using System; |
|
||||||
using System.Security.Cryptography; |
|
||||||
using System.Text; |
|
||||||
|
|
||||||
namespace CA_Platform_Linker.Tools |
|
||||||
{ |
|
||||||
/// <summary> |
|
||||||
/// e签宝开放平台请求签名鉴权工具 |
|
||||||
/// 算法:HmacSHA256 |
|
||||||
/// </summary> |
|
||||||
public static class EsignSignatureHelper |
|
||||||
{ |
|
||||||
/// <summary> |
|
||||||
/// 计算请求签名值 |
|
||||||
/// </summary> |
|
||||||
/// <param name="method">HTTP方法(POST/GET),全大写</param> |
|
||||||
/// <param name="pathAndParameters">接口路径(含query参数),不含host</param> |
|
||||||
/// <param name="body">请求体JSON字符串(GET请求传空字符串)</param> |
|
||||||
/// <param name="appSecret">应用密钥AppSecret</param> |
|
||||||
/// <param name="contentType">Content-Type值,需与实际发送的完全一致</param> |
|
||||||
/// <returns>签名值 + Content-MD5 + 时间戳 的元组</returns> |
|
||||||
public static (string signature, string contentMD5, string timestamp) BuildSignature( |
|
||||||
string method, string pathAndParameters, string body, string appSecret, string contentType) |
|
||||||
{ |
|
||||||
string accept = "*/*"; |
|
||||||
string date = ""; |
|
||||||
string headers = ""; |
|
||||||
|
|
||||||
// 1. 计算Content-MD5(Body的MD5后Base64编码) |
|
||||||
string contentMD5 = string.IsNullOrEmpty(body) ? "" : ComputeContentMD5(body); |
|
||||||
|
|
||||||
// 2. 拼接待签名字符串 |
|
||||||
StringBuilder sb = new StringBuilder(); |
|
||||||
sb.Append(method).Append("\n") |
|
||||||
.Append(accept).Append("\n") |
|
||||||
.Append(contentMD5).Append("\n") |
|
||||||
.Append(contentType).Append("\n") |
|
||||||
.Append(date).Append("\n"); |
|
||||||
|
|
||||||
// Headers为空时不加\n |
|
||||||
sb.Append(headers).Append(pathAndParameters); |
|
||||||
|
|
||||||
string plaintext = sb.ToString(); |
|
||||||
|
|
||||||
// 3. 使用AppSecret进行HmacSHA256计算后Base64编码 |
|
||||||
string signature = HmacSHA256Base64(plaintext, appSecret); |
|
||||||
|
|
||||||
// 4. 毫秒级时间戳 |
|
||||||
string timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(); |
|
||||||
|
|
||||||
return (signature, contentMD5, timestamp); |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary> |
|
||||||
/// 计算Content-MD5:MD5摘要后Base64编码 |
|
||||||
/// </summary> |
|
||||||
private static string ComputeContentMD5(string body) |
|
||||||
{ |
|
||||||
using (MD5 md5 = MD5.Create()) |
|
||||||
{ |
|
||||||
byte[] bytes = Encoding.UTF8.GetBytes(body); |
|
||||||
byte[] hash = md5.ComputeHash(bytes); |
|
||||||
return Convert.ToBase64String(hash); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary> |
|
||||||
/// HmacSHA256计算后Base64编码 |
|
||||||
/// </summary> |
|
||||||
private static string HmacSHA256Base64(string message, string secret) |
|
||||||
{ |
|
||||||
byte[] keyBytes = Encoding.UTF8.GetBytes(secret); |
|
||||||
byte[] messageBytes = Encoding.UTF8.GetBytes(message); |
|
||||||
|
|
||||||
using (HMACSHA256 hmac = new HMACSHA256(keyBytes)) |
|
||||||
{ |
|
||||||
byte[] digestBytes = hmac.ComputeHash(messageBytes); |
|
||||||
return Convert.ToBase64String(digestBytes); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,25 +0,0 @@ |
|||||||
using System.Threading; |
|
||||||
|
|
||||||
namespace CA_Platform_Linker.Tools |
|
||||||
{ |
|
||||||
/// <summary> |
|
||||||
/// SDK初始化状态管理 |
|
||||||
/// </summary> |
|
||||||
public static class SdkState |
|
||||||
{ |
|
||||||
private static int _isInitialized = 0; |
|
||||||
|
|
||||||
/// <summary> |
|
||||||
/// SDK是否已初始化成功 |
|
||||||
/// </summary> |
|
||||||
public static bool IsInitialized => _isInitialized == 1; |
|
||||||
|
|
||||||
/// <summary> |
|
||||||
/// 标记SDK初始化状态 |
|
||||||
/// </summary> |
|
||||||
public static void SetInitialized(bool initialized) |
|
||||||
{ |
|
||||||
Interlocked.Exchange(ref _isInitialized, initialized ? 1 : 0); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
Loading…
Reference in new issue