Skip to content
Bitzsoft.Integrationsbitzsoft.integrations

Concept

ElectronicSignature 电子签章

电子签章域标准三层结构、12 方法统一接口、Result 模式、回调验签/解析双接口与 8 家厂商全量对接指南。

Last updated

ElectronicSignature 域把 8 家电子签章供应商——契约锁、e签宝、法大大、君子签、爱签、上上签、安证通、腾讯电子签——的合同签署能力收拢到一个 12 方法的接口背后。涵盖合同全生命周期、签署流程、印章管理、模板管理和回调验签五个区域。

接口本身走极简模式,复杂场景由厂商扩展方法承接;错误通过统一的 ElectronicSignatureResult<T> 包装;回调通知拆成验签与解析两个独立接口,调用顺序固定。完整 API 清单见 电子签章 API 参考

域结构

Bitzsoft.Integrations.ElectronicSignature ← 抽象层(接口 + 模型 + 异常)
├── Bitzsoft.Integrations.ElectronicSignature.Qiyuesuo ← 契约锁
├── Bitzsoft.Integrations.ElectronicSignature.ESign ← e签宝
├── Bitzsoft.Integrations.ElectronicSignature.Fadada ← 法大大
├── Bitzsoft.Integrations.ElectronicSignature.Junziqian ← 君子签
├── Bitzsoft.Integrations.ElectronicSignature.Asign ← 爱签
├── Bitzsoft.Integrations.ElectronicSignature.BestSign ← 上上签
├── Bitzsoft.Integrations.ElectronicSignature.Anzhengtong ← 安证通
├── Bitzsoft.Integrations.ElectronicSignature.Tencent ← 腾讯电子签
└── Bitzsoft.Integrations.ElectronicSignature.All ← 聚合包

标准三层:抽象层定义接口与共享类型,每家厂商一个实现包,All 聚合包按配置节按需注册。

五个能力区域

IElectronicSignatureProvider 按 5 个业务区域组织,共 12 个方法。异步方法统一用 ElectronicSignatureResult<T> 包装,回调验签是同步方法直接返回 bool

public interface IElectronicSignatureProvider
{
string ProviderName { get; }
// ① 合同管理(5)
Task<ElectronicSignatureResult<string>> CreateContractAsync(SimpleContractRequest request, CancellationToken ct = default);
Task<ElectronicSignatureResult<ContractDetail>> GetContractDetailAsync(string contractId, CancellationToken ct = default);
Task<ElectronicSignatureResult<byte[]>> DownloadContractAsync(string contractId, CancellationToken ct = default);
Task<ElectronicSignatureResult<string>> GetContractViewUrlAsync(string contractId, CancellationToken ct = default);
Task<ElectronicSignatureResult<bool>> CancelContractAsync(string contractId, string? reason = null, CancellationToken ct = default);
// ② 签署(2)
Task<ElectronicSignatureResult<string>> GetSigningUrlAsync(string contractId, string signerId, CancellationToken ct = default);
Task<ElectronicSignatureResult<SigningStatus>> GetSigningStatusAsync(string contractId, CancellationToken ct = default);
// ③ 印章管理(2)
Task<ElectronicSignatureResult<IReadOnlyList<SealInfo>>> ListSealsAsync(string? organizationId = null, CancellationToken ct = default);
Task<ElectronicSignatureResult<SealInfo>> GetSealDetailAsync(string sealId, CancellationToken ct = default);
// ④ 模板管理(2)
Task<ElectronicSignatureResult<IReadOnlyList<TemplateInfo>>> ListTemplatesAsync(int pageIndex = 1, int pageSize = 20, CancellationToken ct = default);
Task<ElectronicSignatureResult<TemplateDetail>> GetTemplateDetailAsync(string templateId, CancellationToken ct = default);
// ⑤ 回调验签(1,同步)
bool VerifyCallback(string signature, string payload,
IDictionary<string, string>? callbackHeaders = null, string? queryString = null);
}

Result 模式

ElectronicSignatureResult<T> 把供应商的成功与失败统一到一个对象里,避免调用方在 try-catch 里区分业务错误和系统异常:

public sealed class ElectronicSignatureResult<T>
{
public bool IsSuccess { get; init; }
public T? Data { get; init; } // 成功时的结果数据
public string? ErrorCode { get; init; } // 供应商原始错误码
public string? ErrorMessage { get; init; } // 错误消息
public static ElectronicSignatureResult<T> Success(T data) => ...;
public static ElectronicSignatureResult<T> Fail(string errorCode, string errorMessage) => ...;
}

供应商实现内部用 ElectronicSignatureException 捕获底层错误,再转成 Fail

public class ElectronicSignatureException : IntegrationException
{
public string ProviderName => Provider ?? string.Empty;
public new string? ErrorCode => base.ErrorCode;
public new string? ProviderMessage => base.ProviderMessage;
public ElectronicSignatureException(string providerName, string? errorCode, string? providerMessage)
: base(domain: "ElectronicSignature",
message: $"[{providerName}] {errorCode}: {providerMessage}",
provider: providerName, errorCode: errorCode, providerMessage: providerMessage) { }
}

也就是说:正常失败走 Fail(如签署方拒签、合同已过期等业务校验),系统级异常才会冒泡抛出。调用方通常只需检查 IsSuccess

回调:验签与解析分离

电子签场景里,签署完成、状态变更等通知由厂商通过 Webhook 回调推送。每家厂商的签名算法和报文格式都不一样,抽象层把回调处理拆成两个独立关注点:

关注点接口返回调用时机
验签(安全闸门)IElectronicSignatureProvider.VerifyCallbackbool信任报文之前
解析(语义转换)IElectronicSignatureCallbackParser.ParseCallbackCallbackEvent验签通过之后
public interface IElectronicSignatureCallbackParser
{
CallbackEvent ParseCallback(string payload);
}

拆分是因为职责不同:验签是安全闸门,必须在信任报文之前完成;解析是语义转换,在信任报文之后提取业务字段。VerifyCallback 的签名之所以带 callbackHeadersqueryString,是因为部分厂商需要请求头里的时间戳或排序后的查询串参与验签计算。

统一事件模型 CallbackEvent

public sealed class CallbackEvent
{
public string ContractId { get; init; } = string.Empty;
public ContractStatus Status { get; init; } // 签署/完成/拒签等
public string? SignerId { get; init; }
public string? RejectReason { get; init; }
public DateTime? EventTime { get; init; }
public string OriginalPayload { get; init; } = string.Empty; // 保留原始报文备查
}

厂商清单

8 家厂商都完整实现了统一接口,每家都同时注册了 IElectronicSignatureProviderIElectronicSignatureCallbackParser 两个能力。验签逻辑内嵌在 Provider 里,解析逻辑在独立的 XxxCallbackParser 类里。

厂商中文Provider IDDI 方法
Qiyuesuo契约锁QiyuesuoAddBitzsoftQiyuesuoElectronicSignature()
ESigne签宝ESignAddBitzsoftESignElectronicSignature()
Fadada法大大FadadaAddBitzsoftFadadaElectronicSignature()
Junziqian君子签JunziqianAddBitzsoftJunziqianElectronicSignature()
Asign爱签AsignAddBitzsoftAsignElectronicSignature()
BestSign上上签BestSignAddBitzsoftBestSignElectronicSignature()
Anzhengtong安证通AnzhengtongAddBitzsoftAnzhengtongElectronicSignature()
Tencent腾讯电子签TencentAddBitzsoftTencentElectronicSignature()

注册

单厂商

// ① 契约锁
builder.Services.AddBitzsoftQiyuesuoElectronicSignature(builder.Configuration.GetSection("ElectronicSignature:Qiyuesuo"));
// ② e签宝
builder.Services.AddBitzsoftESignElectronicSignature(builder.Configuration.GetSection("ElectronicSignature:ESign"));

多厂商聚合

builder.Services.AddBitzsoftElectronicSignatureAll(builder.Configuration, "ElectronicSignature");

All 聚合包按配置节存在性按需注册,配置里写了哪几家就注册哪几家:

{
"ElectronicSignature": {
"Qiyuesuo": { "AppId": "...", "AppSecret": "...", "BaseUrl": "..." },
"ESign": { "AppId": "...", "AppSecret": "...", "BaseUrl": "..." }
}
}

消费

创建并发起签署

public class SigningService(IElectronicSignatureProvider esign)
{
public async Task<string> CreateAndStartAsync(byte[] fileData, string signerName, string signerPhone)
{
var result = await esign.CreateContractAsync(new SimpleContractRequest
{
FileData = fileData,
FileName = "劳动合同.pdf",
Title = "2026 年度劳动合同",
SignerName = signerName,
SignerPhone = signerPhone,
});
if (!result.IsSuccess)
throw new InvalidOperationException($"签署创建失败: {result.ErrorCode} - {result.ErrorMessage}");
return result.Data!; // 返回签署流程 ID
}
}

SimpleContractRequest 支持两种发起来源:传 FileData + FileName 直接上传文件,或传 TemplateId 基于模板发起(二者二选一)。SignerPhone / SignerEmail 至少传一个,供厂商向签署方发送签署通知。供应商特有参数通过 ExtensionParams 字典透传。

回调处理:先验签,再解析

public class CallbackController(
IElectronicSignatureProvider esign,
IElectronicSignatureCallbackParser parser)
{
[HttpPost("webhook/esign")]
public async Task<IActionResult> Handle([FromBody] string payload, [FromHeader] string xSignature)
{
// ① 必须先验签,确认报文可信
if (!esign.VerifyCallback(xSignature, payload))
return Unauthorized();
// ② 验签通过后解析为统一事件
var evt = parser.ParseCallback(payload);
// 根据 evt.Status 更新本地签署记录...
return Ok();
}
}

多厂商路由

public class SigningRouter(IIntegrationProviderResolver<IElectronicSignatureProvider> providers)
{
public async Task<ContractDetail> GetDetailAsync(string vendor, string contractId)
{
var provider = providers.GetRequired(vendor); // "Qiyuesuo" / "ESign" / ...
var result = await provider.GetContractDetailAsync(contractId);
return result.IsSuccess ? result.Data! : throw new InvalidOperationException(result.ErrorMessage);
}
}

合同状态流转

ContractStatus 枚举覆盖了合同的 7 个状态,回调解析后的 CallbackEvent.StatusContractDetail.Status 都用它:

Draft ──创建签署──▶ Signing ──全部签完──▶ Completed
│ ├──拒签──▶ Rejected
├──撤销────▶ Cancelled
└──超时────▶ Expired
任意阶段异常 ──▶ Failed
枚举值含义是否终态
Draft草稿,尚未发起签署
Signing签署中
Completed全部签署方完成
Cancelled已撤销
Rejected已拒签
Expired已过期
Failed签署失败(系统异常)

相关

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%