使用iText 5实现PDF多次签名仅显示最新签名的问题排查
问题分析与解决方案
代码中的问题
- 签名域名称冲突:调用
sap.setVisibleSignature()时第三个参数传null,iText会默认生成签名域名称,多次签名时易出现域名称重复,后续签名会覆盖前一个签名的可视化区域,导致阅读器仅显示最新签名。 - PDF版本参数无效:
PdfStamper.createSignature()的第三个参数传了'0',这是不符合规范的PDF版本标识,会干扰PDF的增量更新机制,影响多签名的兼容性。
实现多签名展示的修改方案
1. 指定唯一签名域名称
每次签名时为setVisibleSignature()的第三个参数传入不同的唯一名称(如"Signature1"、"Signature2"),确保每个签名的可视化区域独立存在,不会被覆盖。
2. 修正PDF版本参数
将PdfStamper.createSignature()的第三个参数改为'\0',表示保留原PDF的版本,避免版本冲突破坏增量签名的逻辑。
3. 保留增量签名模式
代码中最后一个参数append已设为true,这是正确的设置,增量模式会保留之前的签名数据,不会覆盖原有内容。
修改后的示例代码
public List<byte[]> addSign(List<MultipartFile> files, byte[] img, String[] certificates, SignReq signReq, HttpHeaders httpHeaders, AuthorizationReq authorizationReq, String signatureFieldName) throws IOException, DocumentException, GeneralSecurityException { PdfReader reader = new PdfReader(files.get(0).getBytes()); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); // 修正PDF版本参数为'\0',保留原文件版本 PdfStamper stamper = PdfStamper.createSignature(reader, outputStream, '\0', null, true); CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate certificate = ((X509Certificate) cf.generateCertificate( new ByteArrayInputStream(Base64.getDecoder().decode(certificates[0].replaceAll("\n", ""))))); PdfSignatureAppearance sap = stamper.getSignatureAppearance(); sap.setReason("Hihi"); sap.setLocation("Hanoi"); // 传入唯一签名域名称,多次签名使用不同名称 sap.setVisibleSignature(new Rectangle(300, 600, 630, 500), 1, signatureFieldName); sap.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED); ExternalDigest digest = new BouncyCastleDigest(); ExternalSignature signature = new CustomExternalSignature(httpHeaders,signReq,authorizationReq,signatureServices); MakeSignature.signDetached(sap,digest,signature,new Certificate[]{certificate},null,null,null,0, MakeSignature.CryptoStandard.CMS); stamper.close(); reader.close(); List<byte[]> result = new ArrayList<>(); result.add(outputStream.toByteArray()); return result; }
调用说明
第一次签名传入signatureFieldName = "Signature1",第二次签名传入signatureFieldName = "Signature2",同时确保第二次签名的输入文件是第一次签名后的PDF文件,这样每个签名会拥有独立的可视化区域,阅读器即可展示所有签名。
内容的提问来源于stack exchange,提问作者Hoàng Trung Kiên
相关产品推荐
相关产品推荐

