在处理合同、发票或报告时,数字签名能验证文档的完整性与签署人身份。相比手动在Acrobat里逐份签署,用Python批量处理更适合自动化流程。本文基于Spire.PDF for Python,详细介绍如何为PDF添加可见签名、隐藏签名、带时间戳的签名,以及验证签名有效性。
环境准备
首先安装依赖库:还需要一个数字证书文件(.pfx或.p12格式)及对应的密码。测试阶段可使用自签名证书(如通过OpenSSL生成),生产环境应由CA签发。
添加可见的数字签名
可见签名会在PDF页面上绘制一个签名框,显示签署人、原因、位置等信息。核心是PdfOrdinarySignatureMaker对象,它负责加载证书并执行签署运算;签名外观通过PdfSignatureAppearance单独配置。- from spire.pdf import *
- doc = PdfDocument()
- doc.LoadFromFile("SampleB_1.pdf")
- signatureMaker = PdfOrdinarySignatureMaker(doc, "Jerry.pfx", "e-iceblue")
- signature = signatureMaker.Signature
- signature.Name = "Jerry"
- signature.ContactInfo = "028-12345678"
- signature.Location = "Chengdu"
- signature.Reason = "文档负责人签署"
- appearance = PdfSignatureAppearance(signature)
- appearance.NameLabel = "签署人: "
- appearance.ContactInfoLabel = "联系方式: "
- appearance.LocationLabel = "地点: "
- appearance.ReasonLabel = "原因: "
- appearance.SignatureImage = PdfImage.FromFile("logo.png")
- appearance.GraphicMode = GraphicMode.SignImageAndSignDetail
- signatureMaker.MakeSignature("Signer:", doc.Pages.get_Item(0), 90.0, 550.0, 270.0, 90.0, appearance)
- doc.SaveToFile("DigitalSignature.pdf")
- doc.Dispose()
复制代码 关键点:
- Name、Reason、Location等信息写入签名对象,PDF阅读器可读取。
- GraphicMode设置签名框显示内容:SignImageAndSignDetail同时显示Logo和文字,也可只选图片或文字。
- MakeSignature坐标参数以点(point)为单位,原点在页面左下角(左下为(0,0)),四个数值依次为左边界、下边界、宽度、高度。
添加隐藏签名
若只需在文档层面完成完整性校验而不显示可见框,可创建不带外观的隐藏签名。同样使用PdfOrdinarySignatureMaker,只传签名字段名称即可。- from spire.pdf import *
- doc = PdfDocument()
- doc.LoadFromFile("SampleB_1.pdf")
- signatureMaker = PdfOrdinarySignatureMaker(doc, "Jerry.pfx", "e-iceblue")
- signatureMaker.MakeSignature("signName")
- doc.SaveToFile("AddInvisibleSignature.pdf")
- doc.Dispose()
复制代码 隐藏签名仍具备防篡改能力,PDF阅读器可在签名面板中检测到它,但页面无任何显示。
添加带时间戳的签名
数字证书有有效期,若需证明签署发生在证书有效期内,需引入可信时间戳服务(TSA)。Security_PdfSignature提供ConfigureTimestamp方法指定TSA地址。- from spire.pdf import *
- doc = PdfDocument()
- doc.LoadFromFile("SampleB_1.pdf")
- signature = Security_PdfSignature(doc, doc.Pages.get_Item(0), "Jerry.pfx", "e-iceblue", "signature")
- signature.Bounds = RectangleF(PointF(90.0, 550.0), SizeF(180.0, 90.0))
- signature.NameLabel = "Digitally signed by: Jerry"
- signature.Reason = "确保文档真实性"
- signature.DocumentPermissions = PdfCertificationFlags.AllowFormFill.value | PdfCertificationFlags.ForbidChanges.value
- signature.ConfigureTimestamp("https://freetsa.org/tsr")
- doc.SaveToFile("SignedByTimestamp.pdf")
- doc.Dispose()
复制代码 DocumentPermissions属性以证书化签名方式限定签署后允许的操作。示例组合表示“允许继续填写表单字段,但禁止其他改动”,适合审批后仍需收集信息且防止篡改的表单类文档。
验证已签名的文档
遍历PDF表单中的签名字段,调用VerifySignature方法检查文档完整性。- from spire.pdf import *
- doc = PdfDocument()
- doc.LoadFromFile("SignedDocument.pdf")
- formWidget = PdfFormWidget(doc.Form)
- if formWidget.FieldsWidget.Count > 0:
- for i in range(formWidget.FieldsWidget.Count):
- field = formWidget.FieldsWidget.get_Item(i)
- if isinstance(field, PdfField):
- signatureField = PdfSignatureFieldWidget(field)
- valid = doc.VerifySignature(signatureField.FullName)
- print("签名有效" if valid else "签名无效")
- doc.Dispose()
复制代码 VerifySignature会重新计算文档摘要并与签名中的记录比对:若文档被修改,返回无效。
实用建议
- 证书密码不要硬编码:应通过环境变量或密钥管理服务读取。
- 坐标系统:签名框原点在页面左下角,y轴向上为正,与屏幕坐标相反,注意换算。
- 签名顺序:多签名时后续签名会包含先前签名内容,影响验证逻辑。
- 及时释放资源:处理完后调用Dispose(),避免批量任务文件句柄占用。
以上即为Python自动化添加PDF数字签名的完整实现。基于此,可进一步结合表单字段、长期验证(LTV)等构建合同管理、审批流转的自动签署方案。 |