commit
16294ca927
22 changed files with 1814 additions and 0 deletions
@ -0,0 +1,54 @@ |
||||
# 编译输出目录 |
||||
[Dd]ebug/ |
||||
[Rr]elease/ |
||||
bin/ |
||||
obj/ |
||||
|
||||
# .NET 生成文件 |
||||
*.cs.user |
||||
*.csproj.user |
||||
*.suo |
||||
*.user |
||||
*.userosscache |
||||
*.sln.docstates |
||||
|
||||
# Visual Studio |
||||
.vs/ |
||||
*.swp |
||||
*.vspx |
||||
*.vspscc |
||||
*.vssscc |
||||
_ReSharper*/ |
||||
*.ReSharper* |
||||
|
||||
# Rider / JetBrains |
||||
.idea/ |
||||
*.iml |
||||
*.iws |
||||
*.xml |
||||
|
||||
# VS Code |
||||
.vscode/ |
||||
*.code-workspace |
||||
|
||||
# 日志 |
||||
logs/ |
||||
*.log |
||||
|
||||
# 临时文件 |
||||
*.tmp |
||||
*.temp |
||||
|
||||
# 操作系统文件 |
||||
.DS_Store |
||||
Thumbs.db |
||||
|
||||
# dotnet tools 本地安装 |
||||
.dotnet/ |
||||
|
||||
# NuGet |
||||
*.nupkg |
||||
.nuget/ |
||||
|
||||
# 测试覆盖率 |
||||
coverage/ |
||||
@ -0,0 +1,23 @@ |
||||
<Project Sdk="Microsoft.NET.Sdk.Web"> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
<RootNamespace>CA_Platform_Linker</RootNamespace> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.1.5" /> |
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" /> |
||||
<PackageReference Include="NLog" Version="4.7.15" /> |
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.9.3" /> |
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<Content Update="nlog.config"> |
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> |
||||
</Content> |
||||
</ItemGroup> |
||||
|
||||
|
||||
</Project> |
||||
@ -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}" |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,78 @@ |
||||
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; } |
||||
} |
||||
} |
||||
@ -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; } |
||||
} |
||||
} |
||||
@ -0,0 +1,24 @@ |
||||
using System; |
||||
|
||||
namespace CA_Platform_Linker.Models |
||||
{ |
||||
public class SignInfo |
||||
{ |
||||
public long KeyNo { get; set; } |
||||
public int TextType { get; set; } |
||||
public int MZNum { get; set; } |
||||
public int ZYNum { get; set; } |
||||
public string SourceText { get; set; } |
||||
public string Base64Text { get; set; } |
||||
public string OperCode { get; set; } |
||||
public string OperName { get; set; } |
||||
public string SignDate { get; set; } |
||||
public string CertID { get; set; } |
||||
public string OperCert { get; set; } |
||||
public string SignData { get; set; } |
||||
public string TSData { get; set; } |
||||
public string SignID { get; set; } |
||||
public string OperType { get; set; } |
||||
public int SignWay { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,272 @@ |
||||
# CA平台链接器服务 |
||||
|
||||
这是一个客户端程序和CA服务中间的信息交互服务,提供登录验证、自动签名开启和字符串签名功能。 |
||||
|
||||
## 功能特性 |
||||
|
||||
1. **登录验证** - 支持扫码登录 |
||||
2. **自动签名开启** - 开启自动签名功能 |
||||
3. **字符串签名** - 支持多种签名方式 |
||||
4. **Base64编码/解码** - 提供数据转换工具 |
||||
5. **时间戳服务** - 创建时间戳 |
||||
|
||||
## API接口 |
||||
|
||||
### 1. 登录验证 |
||||
**接口**: `POST /Client/Login` |
||||
|
||||
**请求体**: |
||||
```json |
||||
{ |
||||
"account": "test", |
||||
"password": "123456" |
||||
} |
||||
``` |
||||
|
||||
**响应**: |
||||
```json |
||||
{ |
||||
"success": true, |
||||
"message": "登录成功,请扫码", |
||||
"signDataId": "xxx", |
||||
"qrCode": "xxx" |
||||
} |
||||
``` |
||||
|
||||
### 2. 添加签名任务 |
||||
**接口**: `POST /Client/AddSignJob` |
||||
|
||||
**请求体**: |
||||
```json |
||||
{ |
||||
"title": "测试签名", |
||||
"data": "要签名的数据", |
||||
"userId": "用户ID(可选)", |
||||
"algo": "SM3withSM2", |
||||
"expiryDate": "1400" |
||||
} |
||||
``` |
||||
|
||||
**响应**: |
||||
```json |
||||
{ |
||||
"success": true, |
||||
"message": "添加签名任务成功", |
||||
"signDataId": "xxx", |
||||
"qrCode": "xxx" |
||||
} |
||||
``` |
||||
|
||||
### 3. 自动签名 |
||||
**接口**: `POST /Client/AutoSign` |
||||
|
||||
**请求体**: |
||||
```json |
||||
{ |
||||
"userId": "用户ID", |
||||
"signToken": "签名令牌", |
||||
"data": "要签名的数据", |
||||
"algo": "SM3withSM2", |
||||
"expiryDate": "1400" |
||||
} |
||||
``` |
||||
|
||||
**响应**: |
||||
```json |
||||
{ |
||||
"success": true, |
||||
"message": "自动签名成功", |
||||
"signResult": "签名结果", |
||||
"signCert": "签名证书", |
||||
"signDataId": "xxx" |
||||
} |
||||
``` |
||||
|
||||
### 4. 获取签名结果 |
||||
**接口**: `POST /Client/GetSignResult` |
||||
|
||||
**请求体**: |
||||
```json |
||||
{ |
||||
"signDataId": "签名数据ID" |
||||
} |
||||
``` |
||||
|
||||
**响应**: |
||||
```json |
||||
{ |
||||
"success": true, |
||||
"message": "获取签名结果成功", |
||||
"jobStatus": "FINISH", |
||||
"signResult": "签名结果", |
||||
"signCert": "签名证书", |
||||
"userId": "用户ID" |
||||
} |
||||
``` |
||||
|
||||
### 5. 查询签名图片 |
||||
**接口**: `POST /Client/QueryImage` |
||||
|
||||
**请求体**: `"用户ID"` |
||||
|
||||
**响应**: |
||||
```json |
||||
{ |
||||
"success": true, |
||||
"message": "查询签名图片成功", |
||||
"image": "base64图片数据" |
||||
} |
||||
``` |
||||
|
||||
### 6. Base64编码 |
||||
**接口**: `POST /Client/Base64Encode` |
||||
|
||||
**请求体**: |
||||
```json |
||||
{ |
||||
"plainText": "要编码的文本" |
||||
} |
||||
``` |
||||
|
||||
**响应**: |
||||
```json |
||||
{ |
||||
"success": true, |
||||
"message": "Base64编码成功", |
||||
"base64Data": "编码后的数据" |
||||
} |
||||
``` |
||||
|
||||
### 7. Base64解码 |
||||
**接口**: `POST /Client/Base64Decode` |
||||
|
||||
**请求体**: |
||||
```json |
||||
{ |
||||
"base64Data": "要解码的Base64数据" |
||||
} |
||||
``` |
||||
|
||||
**响应**: |
||||
```json |
||||
{ |
||||
"success": true, |
||||
"message": "Base64解码成功", |
||||
"plainText": "解码后的文本" |
||||
} |
||||
``` |
||||
|
||||
### 8. 创建时间戳 |
||||
**接口**: `POST /Client/CreateTss` |
||||
|
||||
**请求体**: |
||||
```json |
||||
{ |
||||
"oriData": "原文数据", |
||||
"attachCert": true |
||||
} |
||||
``` |
||||
|
||||
**响应**: |
||||
```json |
||||
{ |
||||
"success": true, |
||||
"message": "创建时间戳成功", |
||||
"tsResp": "时间戳响应" |
||||
} |
||||
``` |
||||
|
||||
## 配置说明 |
||||
|
||||
在 `appsettings.json` 中配置CA服务相关参数: |
||||
|
||||
```json |
||||
{ |
||||
"CossBaseUrl": "https://newcoss-dev.isignet.cn:10201/coss/service/v1/", |
||||
"CossAppId": "APP_7B3F36A14E99410A80B37AEF332E3247", |
||||
"CossSecureCode": "DLwiH46Esb8ccNTkuSSVAadNTWUfW0sc", |
||||
"CossSignAlgo": "HMAC", |
||||
"CossVersion": "1.0" |
||||
} |
||||
``` |
||||
|
||||
## 使用示例 |
||||
|
||||
### 1. 启动服务 |
||||
```bash |
||||
dotnet run |
||||
``` |
||||
|
||||
### 2. 访问Swagger文档 |
||||
打开浏览器访问: `http://localhost:5000/LISPlatformLinker/swagger` |
||||
|
||||
### 3. 调用API示例 |
||||
|
||||
#### 登录并获取二维码 |
||||
```bash |
||||
curl -X POST "http://localhost:5000/LISPlatformLinker/Client/Login" \ |
||||
-H "Content-Type: application/json" \ |
||||
-d '{"account":"test","password":"123456"}' |
||||
``` |
||||
|
||||
#### 添加签名任务 |
||||
```bash |
||||
curl -X POST "http://localhost:5000/LISPlatformLinker/Client/AddSignJob" \ |
||||
-H "Content-Type: application/json" \ |
||||
-d '{"title":"测试签名","data":"Hello World","algo":"SM3withSM2"}' |
||||
``` |
||||
|
||||
#### 自动签名 |
||||
```bash |
||||
curl -X POST "http://localhost:5000/LISPlatformLinker/Client/AutoSign" \ |
||||
-H "Content-Type: application/json" \ |
||||
-d '{"userId":"xxx","signToken":"xxx","data":"Hello World"}' |
||||
``` |
||||
|
||||
## 项目结构 |
||||
|
||||
``` |
||||
CA-Platform-Linker/ |
||||
├── Controllers/ |
||||
│ └── ClientController.cs # 客户端控制器 |
||||
├── Models/ |
||||
│ ├── Coss/ |
||||
│ │ └── CossModels.cs # CA服务模型 |
||||
│ └── DTO/ |
||||
│ └── ClientDto.cs # 客户端DTO |
||||
├── Services/ |
||||
│ ├── Interfaces/ |
||||
│ │ └── IClientService.cs # 客户端服务接口 |
||||
│ └── ClientService.cs # 客户端服务实现 |
||||
├── Tools/ |
||||
│ ├── CossHelper.cs # CA服务帮助类 |
||||
│ ├── ConfigHelper.cs # 配置帮助类 |
||||
│ └── MySecurity.cs # 安全类 |
||||
└── appsettings.json # 配置文件 |
||||
``` |
||||
|
||||
## 注意事项 |
||||
|
||||
1. 所有接口都使用POST方法 |
||||
2. 请求和响应都使用JSON格式 |
||||
3. 签名数据会自动进行Base64编码 |
||||
4. 需要正确配置CA服务的连接参数 |
||||
5. 建议在生产环境中使用HTTPS协议 |
||||
|
||||
## 错误处理 |
||||
|
||||
所有接口都包含错误处理,当请求失败时会返回错误信息: |
||||
|
||||
```json |
||||
{ |
||||
"success": false, |
||||
"message": "错误描述" |
||||
} |
||||
``` |
||||
|
||||
## 日志 |
||||
|
||||
使用NLog进行日志记录,日志文件位于 `logs/` 目录下: |
||||
- `logs/info/` - 信息日志 |
||||
- `logs/error/` - 错误日志 |
||||
- `logs/debug/` - 调试日志 |
||||
@ -0,0 +1,160 @@ |
||||
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(() => |
||||
{ |
||||
try |
||||
{ |
||||
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 = "", |
||||
OperCert = result.data.signCert, |
||||
SignData = result.data.signResult, |
||||
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 |
||||
}; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,16 @@ |
||||
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); |
||||
} |
||||
} |
||||
@ -0,0 +1,86 @@ |
||||
using CA_Platform_Linker.Services; |
||||
using CA_Platform_Linker.Services.Interfaces; |
||||
using CA_Platform_Linker.Tools; |
||||
using Microsoft.AspNetCore.Builder; |
||||
using Microsoft.AspNetCore.Hosting; |
||||
using Microsoft.AspNetCore.Mvc; |
||||
using Microsoft.Extensions.Configuration; |
||||
using Microsoft.Extensions.DependencyInjection; |
||||
using Microsoft.Extensions.Hosting; |
||||
using Microsoft.Extensions.Logging; |
||||
using Microsoft.OpenApi.Models; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace CA_Platform_Linker |
||||
{ |
||||
public class Startup |
||||
{ |
||||
public Startup(IConfiguration configuration) |
||||
{ |
||||
Configuration = configuration; |
||||
} |
||||
|
||||
public IConfiguration Configuration { get; } |
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container. |
||||
public void ConfigureServices(IServiceCollection services) |
||||
{ |
||||
//读取配置 |
||||
ConfigHelper.Initialize(Configuration); |
||||
|
||||
//初始化数据库连接 |
||||
SqlHelper.Initialize(Configuration); |
||||
|
||||
services.AddControllers(); |
||||
|
||||
//注册服务 |
||||
services.AddTransient<IClientService, ClientService>(); |
||||
|
||||
services.AddSwaggerGen(s => |
||||
{ |
||||
//标记swagger 信息(内容自定义) |
||||
//V1.0.0-->SwaggerEndpoint(url,name)-->url 使用 |
||||
s.SwaggerDoc("V1.0.0", new Microsoft.OpenApi.Models.OpenApiInfo |
||||
{ |
||||
Title = "CA平台连接服务", |
||||
Version = "1.0.0", |
||||
}); |
||||
s.AddServer(new OpenApiServer |
||||
{ |
||||
Url = "/CAPlatformLinker", |
||||
Description = "API全局路由" |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. |
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) |
||||
{ |
||||
if (env.IsDevelopment()) |
||||
{ |
||||
app.UseDeveloperExceptionPage(); |
||||
} |
||||
|
||||
app.UsePathBase("/CAPlatformLinker"); |
||||
|
||||
app.UseSwagger(); |
||||
app.UseSwaggerUI(su => |
||||
{ |
||||
//url中[V1.0.0]与ConfigureServices 中配置的SwaggerDoc("V1.0.0",..) 保持一致 |
||||
su.SwaggerEndpoint("/swagger/V1.0.0/swagger.json", null); |
||||
}); |
||||
|
||||
app.UseRouting(); |
||||
|
||||
app.UseAuthorization(); |
||||
|
||||
app.UseEndpoints(endpoints => |
||||
{ |
||||
endpoints.MapControllers(); |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,68 @@ |
||||
using Microsoft.Extensions.Configuration; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace CA_Platform_Linker.Tools |
||||
{ |
||||
public static class ConfigHelper |
||||
{ |
||||
private static IConfiguration _config; |
||||
|
||||
public static void Initialize(IConfiguration configuration) |
||||
{ |
||||
_config = configuration; |
||||
} |
||||
|
||||
// LIS数据库连接字符串 |
||||
public static string ConnectionString => MySecurity.SDecryptString(_config.GetValue<string>("ConnectionString")); |
||||
|
||||
// 检验平台接口地址 |
||||
public static string PlatformUrl => _config.GetValue<string>("PlatformUrl"); |
||||
|
||||
// 医疗机构代码 |
||||
public static string HospitalCode => _config.GetValue<string>("HospitalCode"); |
||||
|
||||
// 医疗机构名称 |
||||
public static string HospitalName => _config.GetValue<string>("HospitalName"); |
||||
|
||||
// CA服务基础配置 |
||||
public static string CossBaseUrl => _config.GetValue<string>("CossBaseUrl", "http://192.168.0.148:10201/coss/service/v1/"); |
||||
public static string CossSignAlgo => _config.GetValue<string>("CossSignAlgo", "HMAC"); |
||||
public static string CossVersion => _config.GetValue<string>("CossVersion", "1.0"); |
||||
|
||||
// 获取指定客户端的配置 |
||||
public static CossClientConfig GetCossClientConfig(string clientType) |
||||
{ |
||||
var clientsSection = _config.GetSection("CossClients"); |
||||
var clientSection = clientsSection.GetSection(clientType); |
||||
|
||||
if (!clientSection.Exists()) |
||||
{ |
||||
throw new ArgumentException($"未找到客户端类型 '{clientType}' 的配置"); |
||||
} |
||||
|
||||
return new CossClientConfig |
||||
{ |
||||
AppId = clientSection.GetValue<string>("AppId"), |
||||
SecureCode = clientSection.GetValue<string>("SecureCode"), |
||||
TextType = clientSection.GetValue<int>("TextType", 0) |
||||
}; |
||||
} |
||||
|
||||
// 获取所有支持的客户端类型 |
||||
public static List<string> GetSupportedClientTypes() |
||||
{ |
||||
var clientsSection = _config.GetSection("CossClients"); |
||||
return clientsSection.GetChildren().Select(x => x.Key).ToList(); |
||||
} |
||||
} |
||||
|
||||
public class CossClientConfig |
||||
{ |
||||
public string AppId { get; set; } |
||||
public string SecureCode { get; set; } |
||||
public int TextType { get; set; } |
||||
} |
||||
} |
||||
@ -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); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,13 @@ |
||||
using NLog; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace CA_Platform_Linker.Tools |
||||
{ |
||||
public class LogHelper |
||||
{ |
||||
public static readonly NLog.Logger Log = LogManager.GetCurrentClassLogger(); |
||||
} |
||||
} |
||||
@ -0,0 +1,89 @@ |
||||
using CA_Platform_Linker.Models; |
||||
using Microsoft.Data.SqlClient; |
||||
using Microsoft.Extensions.Configuration; |
||||
using System; |
||||
|
||||
namespace CA_Platform_Linker.Tools |
||||
{ |
||||
public static class SqlHelper |
||||
{ |
||||
private static string _connectionString; |
||||
|
||||
public static void Initialize(IConfiguration configuration) |
||||
{ |
||||
_connectionString = configuration.GetConnectionString("HisDB"); |
||||
} |
||||
|
||||
public static int InsertSignInfo(SignInfo signInfo) |
||||
{ |
||||
if (string.IsNullOrEmpty(_connectionString)) |
||||
{ |
||||
throw new InvalidOperationException("数据库连接字符串未配置"); |
||||
} |
||||
|
||||
string sql = @"INSERT INTO [DigitalSignData].[dbo].[SignInfo]
|
||||
([TextType], [MZNum], [ZYNum], [SourceText], [Base64Text], |
||||
[OperCode], [OperName], [SignDate], [CertID], [OperCert], |
||||
[SignData], [TSData], [SignID], [OperType], [SignWay]) |
||||
VALUES |
||||
(@TextType, @MZNum, @ZYNum, @SourceText, @Base64Text, |
||||
@OperCode, @OperName, @SignDate, @CertID, @OperCert, |
||||
@SignData, @TSData, @SignID, @OperType, @SignWay)";
|
||||
|
||||
using (SqlConnection conn = new SqlConnection(_connectionString)) |
||||
{ |
||||
using (SqlCommand cmd = new SqlCommand(sql, conn)) |
||||
{ |
||||
cmd.Parameters.AddWithValue("@TextType", signInfo.TextType); |
||||
cmd.Parameters.AddWithValue("@MZNum", signInfo.MZNum); |
||||
cmd.Parameters.AddWithValue("@ZYNum", signInfo.ZYNum); |
||||
cmd.Parameters.AddWithValue("@SourceText", (object)signInfo.SourceText ?? DBNull.Value); |
||||
cmd.Parameters.AddWithValue("@Base64Text", (object)signInfo.Base64Text ?? DBNull.Value); |
||||
cmd.Parameters.AddWithValue("@OperCode", (object)signInfo.OperCode ?? DBNull.Value); |
||||
cmd.Parameters.AddWithValue("@OperName", (object)signInfo.OperName ?? DBNull.Value); |
||||
cmd.Parameters.AddWithValue("@SignDate", (object)signInfo.SignDate ?? DBNull.Value); |
||||
cmd.Parameters.AddWithValue("@CertID", (object)signInfo.CertID ?? DBNull.Value); |
||||
cmd.Parameters.AddWithValue("@OperCert", (object)signInfo.OperCert ?? DBNull.Value); |
||||
cmd.Parameters.AddWithValue("@SignData", (object)signInfo.SignData ?? DBNull.Value); |
||||
cmd.Parameters.AddWithValue("@TSData", (object)signInfo.TSData ?? DBNull.Value); |
||||
cmd.Parameters.AddWithValue("@SignID", (object)signInfo.SignID ?? DBNull.Value); |
||||
cmd.Parameters.AddWithValue("@OperType", (object)signInfo.OperType ?? DBNull.Value); |
||||
cmd.Parameters.AddWithValue("@SignWay", signInfo.SignWay); |
||||
|
||||
conn.Open(); |
||||
return cmd.ExecuteNonQuery(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public static (string operCode, string operName) GetOperatorInfo(string bjcaMsspid) |
||||
{ |
||||
if (string.IsNullOrEmpty(_connectionString)) |
||||
{ |
||||
throw new InvalidOperationException("数据库连接字符串未配置"); |
||||
} |
||||
|
||||
string sql = @"SELECT [CODE], [NAME]
|
||||
FROM [HisData].[dbo].[YSCODE] |
||||
WHERE [BJCA_MSSPID] = @BJCA_MSSPID";
|
||||
|
||||
using (SqlConnection conn = new SqlConnection(_connectionString)) |
||||
{ |
||||
using (SqlCommand cmd = new SqlCommand(sql, conn)) |
||||
{ |
||||
cmd.Parameters.AddWithValue("@BJCA_MSSPID", bjcaMsspid); |
||||
conn.Open(); |
||||
using (var reader = cmd.ExecuteReader()) |
||||
{ |
||||
if (reader.Read()) |
||||
{ |
||||
return (reader["CODE"].ToString(), reader["NAME"].ToString()); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return (null, null); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,9 @@ |
||||
{ |
||||
"Logging": { |
||||
"LogLevel": { |
||||
"Default": "Information", |
||||
"Microsoft": "Warning", |
||||
"Microsoft.Hosting.Lifetime": "Information" |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,38 @@ |
||||
{ |
||||
"Logging": { |
||||
"LogLevel": { |
||||
"Default": "Information", |
||||
"Microsoft": "Warning", |
||||
"Microsoft.Hosting.Lifetime": "Information" |
||||
} |
||||
}, |
||||
"AllowedHosts": "*", |
||||
"ConnectionStrings": { |
||||
"HisDB": "Data Source=192.168.0.222;User ID=XBDLisUser;Password=BlueFlag.Lis!@#;TrustServerCertificate=True" |
||||
}, |
||||
"CossBaseUrl": "http://192.168.0.148:10201/coss/service/v1/", |
||||
"CossSignAlgo": "HMAC", |
||||
"CossVersion": "1.0", |
||||
"CossClients": { |
||||
"LIS": { |
||||
"AppId": "APP_E559E1B8906045D4881D74F29361F6BB", |
||||
"SecureCode": "MGI0ODQ0NjYxZjg1NDgzZDhkMDNjYzI5YTM4MDA0ZDk=", |
||||
"TextType": 500 |
||||
}, |
||||
"PEIS": { |
||||
"AppId": "APP_6E254EA9538743088BD393C3D0212617", |
||||
"SecureCode": "OTdhMDRkMmY1YzVmNDczY2FlZjhhOWE5NmY1OTI2MzY=", |
||||
"TextType": 700 |
||||
}, |
||||
"Blood": { |
||||
"AppId": "APP_855883154E16433EBE12B8C73822AE17", |
||||
"SecureCode": "YjI1YjVkYTQ5OWMwNDYxOTkwY2MwZTUyYTkxMzc2MWU=", |
||||
"TextType": 600 |
||||
}, |
||||
"WeChat": { |
||||
"AppId": "APP_E56656ADD9DE48779F21D9FE50529E3A", |
||||
"SecureCode": "OTczNzkyMWNlMzk2NGE3YjgyMTdkMzRkNzBmODllNTk=", |
||||
"TextType": 800 |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue