使用PDFBox添加所有者密码保护的PDF,readAllBytes读取后保护失效求助
问题描述
我使用PDFBox的StandardProtectionPolicy为PDF文档添加所有者密码保护(仅允许阅读,禁止编辑、打印等操作),保存后的outputPdf文件确实带有预期的保护,但通过Files.readAllBytes读取该文件的字节并返回给调用方后,发现所有密码保护都消失了。
加密代码如下:
PDDocument pdDocument = PDDocument.load(new File(inputPdf)); AccessPermission accessPermission = new AccessPermission(); accessPermission.setCanModify(false); accessPermission.setCanPrint(false); // 禁止打印 accessPermission.setCanExtractContent(false); accessPermission.setCanPrintDegraded(false); accessPermission.setReadOnly(); StandardProtectionPolicy spp = new StandardProtectionPolicy(password, "", accessPermission); spp.setEncryptionKeyLength(128); pdDocument.protect(spp); pdDocument.save(new java.io.File(outputPdf)); // 关闭文档 pdDocument.close();
我还尝试过设置操作系统级的文件写保护,没有效果:
File file = new File(outputPdf); // 设置文件权限 file.setReadable(true); // 允许读取 file.setWritable(false); // 禁止写入 file.setExecutable(true);
返回字节的代码:
return Files.readAllBytes(Path.of(outputPdf)); // 执行后所有所有者密码保护消失
请问如何在不丢失保护的情况下返回文件字节?
解决方案
核心原因
Files.readAllBytes本身不会移除PDF的加密保护,问题出在你的验证逻辑上:你代码里设置了空的用户密码(StandardProtectionPolicy的第二个参数为空字符串),这意味着PDF阅读器可以直接无密码打开文档,并且自动解密展示,让你误以为保护消失了,但实际上PDF的权限限制依然存在。
具体修复步骤
修正加密策略的参数设置
你当前的代码中,StandardProtectionPolicy(password, "", accessPermission)的第二个参数是空字符串,代表用户无需密码即可打开文档,仅受权限限制。如果需要用户输入密码才能打开,需将第二个参数设置为用户密码:// ownerPassword:所有者密码,用于解锁所有权限;userPassword:用户密码,用于打开文档 StandardProtectionPolicy spp = new StandardProtectionPolicy(ownerPassword, userPassword, accessPermission);若保持无用户密码的需求,权限限制依然有效,只是阅读器会自动解密展示,但无法执行编辑、打印等受限操作。
直接返回原始字节即可
Files.readAllBytes读取的是文件的原始字节流,完全保留了PDF的加密信息。你可以通过以下方式验证:- 将返回的字节写入新文件,用PDF阅读器打开并尝试编辑/打印,查看是否被禁止;
- 用PDFBox加载字节流,检查加密状态:
PDDocument doc = PDDocument.load(byteArray); System.out.println("文档是否加密:" + doc.isEncrypted()); doc.close();
移除无效的系统级权限设置
file.setWritable(false)是操作系统层面的文件写保护,和PDF本身的加密权限无关,可直接删除这部分代码,它不会影响PDF的权限控制。
内容的提问来源于stack exchange,提问作者user1272435

