itext7设置pdf打开密码必须调用setstandardencryption()并传入完整参数,仅设userpassword无效;权限限制依赖ownerpassword强度且实际防打印效果有限,中文密码需utf-8编码,字体须显式嵌入以防乱码。

用 iText7 的 PdfWriter 设置打开密码(UserPassword)必须启用加密器
不显式创建 StandardEncryption 实例,PdfWriter 就不会加密——哪怕你传了 userPassword 参数。常见错误是只写 new PdfWriter(dest, new WriterProperties().setUserPassword("123")),结果 PDF 完全没加密。
正确做法是:在 WriterProperties 中调用 setStandardEncryption(),并传入完整参数。4 个 byte 数组参数不能为 null,即使你想用默认值也要填 new byte[0]。
-
userPassword:控制打开文档(即“打开密码”),设为空字节数组new byte[0]表示无打开密码 -
ownerPassword:控制权限修改(如删水印、改权限),建议非空,否则无法限制打印/编辑 -
permissions:用PdfWriter静态字段组合,例如PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_COPY -
encryptionAlgorithm:推荐EncryptionConstants.STANDARD_ENCRYPTION_128(AES-128),别用已淘汰的 40 位
PdfWriter writer = new PdfWriter(dest, new WriterProperties()
.setStandardEncryption(
"reader".getBytes(), // user password
"admin".getBytes(), // owner password
PdfWriter.ALLOW_PRINTING,
EncryptionConstants.STANDARD_ENCRYPTION_128
)
);
禁止打印但允许复制文字?iText7 的权限位不是布尔开关
iText7 的权限模型基于 Adobe 的 PDF 规范,ALLOW_PRINTING 和 ALLOW_COPY 是独立位,但受 ownerPassword 保护——如果 ownerPassword 为空或弱,PDF 阅读器(如 Adobe Acrobat)可能忽略这些限制。
更关键的是:现代阅读器(尤其是移动端)普遍不强制执行打印限制。Chrome 内置 PDF 查看器、Edge、Foxit 等大多会跳过权限检查,仅校验打开密码。所以「禁止打印」在实际中只能防小白,不能防截图或另存为图片。
- 真正有效的防护只有打开密码(
userPassword)+ 强 ownerPassword -
ALLOW_MODIFY_CONTENTS对表单填写无效;带表单的 PDF 需额外调用pdfDoc.GetCatalog().SetAcroForm(...)并设setNeedAppearances(true) - 若目标是彻底禁用打印,得配合 DRM 方案(如 Azure Information Protection),iText7 做不到
中文密码乱码?setUserPassword() 接收 byte[],不是 string
iText7 所有密码方法都要求 byte[],直接传 "密码123" 字符串会按平台默认编码(如 Windows-1252)转字节,导致 PDF 在其他系统打不开。
必须统一用 UTF-8 编码转换:
string pwd = "你好123"; byte[] userBytes = Encoding.UTF8.GetBytes(pwd);
注意:ownerPassword 同样要 UTF-8;如果和旧系统(如 iText5)交互,对方用 Latin-1,就得协调编码,否则互相打不开。
- 测试时用 Adobe Acrobat 打开 → 文件 → 属性 → 安全 → 查看实际应用的加密算法和权限位
- 不要依赖预览缩略图或浏览器右键菜单判断是否生效——它们常缓存未加密版本
加密后字体丢失或文字变方块?PDF/A 兼容性与嵌入策略冲突
启用加密后,iText7 默认关闭字体子集嵌入(subset),尤其对非 ASCII 字符(如中文字体)影响明显。如果源字体未完全嵌入,Acrobat 可能回退到默认字体,显示为方块或乱码。
解决办法是在 PdfFontFactory 创建字体时强制嵌入:
PdfFont font = PdfFontFactory.CreateFont(
"simhei.ttf",
PdfEncodings.IDENTITY_H,
true // embed = true
);
- 务必设第三个参数为
true,否则加密 + 中文 = 显示异常 - 避免使用系统字体名(如
"SimHei"),应提供真实路径的 TTF 文件 - PDF/A 模式(
new PdfWriter(..., new WriterProperties().setPdfVersion(PdfVersion.PDF_1_7).setPdfAConformance(PdfAConformance.PDF_A_1_A)))下加密更严格,需额外验证字体许可证和元数据
加密本身不改变字体逻辑,但会放大嵌入疏漏——这是最容易被忽略的环节。










