合同、报价单、财务报表这类文件一旦以 PDF 外发,内容基本就处在敞口状态——谁都能打开,也谁都能另存一份、改完再发出去。要在分发环节收一道口子,最直接的做法是给文档设密码,或者只放开阅读、把打印和复制关掉。这些操作过去要么依赖桌面软件,要么把文件传到服务端处理:前者很难嵌进 Web 流程,后者则意味着文档离开了用户的设备。
Spire.PDF for JavaScript 基于 WebAssembly 在浏览器端直接加载、修改与保存 PDF 文档,加密过程全部在本地完成,通过虚拟文件系统(VFS)读写文件,无需后端配合。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.PDF for JavaScript。以下示例默认已安装 Spire.PDF 并完成 WebAssembly 模块初始化。
加密 PDF 文档
PdfPasswordSecurityPolicy 的构造函数接收打开密码与权限密码两个参数:拿到文档的一方需要前者才能打开,后者留给文档所有者,用于日后解除限制。加密算法通过 EncryptionAlgorithm 指定,这里选用 AES-128;DocumentPrivilege 则决定文档打开后允许执行哪些操作,get_AllowAll() 表示全部放行。
function App() {
const encryptPdf = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将待加密的 PDF 文件载入 VFS
const inputFileName = '合同模板.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象并加载 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 创建密码安全策略:第一个参数是打开密码,第二个是权限密码
const policy = new pdfModule.PdfPasswordSecurityPolicy('spire123', 'owner123');
// 指定加密算法
policy.EncryptionAlgorithm = pdfModule.PdfEncryptionAlgorithm.AES_128;
// 指定权限策略,get_AllowAll() 表示不限制任何操作
policy.DocumentPrivilege = pdfModule.PdfDocumentPrivilege.get_AllowAll();
// 应用加密策略并保存文档
doc.Encrypt(policy);
const outputFileName = '加密文档.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// 从 VFS 读取生成的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>加密 PDF 文档</h1>
<button onClick={encryptPdf}>
开始加密
</button>
</div>
);
}
export default App;
设置打开密码与权限密码后的 PDF 文档

限制 PDF 文档的操作权限
把打开密码留空、只设权限密码,文档就能免密打开,但打印、复制、修改这些操作会按权限设置逐项放行或禁止,很适合“可以看、带不走”的分发场景。权限本身用 PdfDocumentPrivilege 描述:先取一套全部放行的基准,再关掉不需要的项,这里关掉的是打印、复制内容和修改内容。
function App() {
const restrictPdfPermissions = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将待处理的 PDF 文件载入 VFS
const inputFileName = '合同模板.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象并加载 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 打开密码留空:文档可以直接打开;权限密码用于日后解除限制
const policy = new pdfModule.PdfPasswordSecurityPolicy('', 'owner123');
policy.EncryptionAlgorithm = pdfModule.PdfEncryptionAlgorithm.AES_128;
// 以全部放行为基准,逐项关闭不需要的权限
const privilege = pdfModule.PdfDocumentPrivilege.get_AllowAll();
privilege.AllowPrint = false;
privilege.AllowContentCopying = false;
privilege.AllowModifyContents = false;
policy.DocumentPrivilege = privilege;
// 应用加密策略并保存文档
doc.Encrypt(policy);
const outputFileName = '权限受限文档.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// 从 VFS 读取生成的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>限制 PDF 操作权限</h1>
<button onClick={restrictPdfPermissions}>
开始设置
</button>
</div>
);
}
export default App;
免密码打开、但打印与复制等操作已被禁止的 PDF 文档

解密 PDF 文档
解密就是把已有的密码保护去掉,前提是拿得到密码。如果手上只有打开密码,Decrypt 需要再给出权限密码才能解除限制,只凭打开密码调用无参的 Decrypt() 会被拒绝。
function App() {
const decryptPdf = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将待解密的 PDF 文件载入 VFS
const inputFileName = '加密合同.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象,并用打开密码载入加密文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName, 'spire123');
// 确认文档确实受密码保护
if (!doc.IsEncrypted) {
alert('该文档未加密,无需解密');
return;
}
// 用权限密码移除密码保护
doc.Decrypt('owner123');
const outputFileName = '解密文档.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// 从 VFS 读取生成的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>解密 PDF 文档</h1>
<button onClick={decryptPdf}>
开始解密
</button>
</div>
);
}
export default App;
移除密码保护后的 PDF 文档,可直接打开

常见问题
打开加密文档时提示密码无效
原因:调用 LoadFromFile 时没有传密码,或者传进去的密码与文档的打开密码不一致。这种情况下 Spire.PDF 会直接抛出 Can not open an encrypted document. The password is invalid.,而不会返回一个内容为空的 PdfDocument。
解决:把打开密码作为 LoadFromFile 的第二个参数传入即可:
// 第二个参数即打开密码
doc.LoadFromFile(inputFileName, 'spire123');
调用 Decrypt() 时报 "Cannot decrypt documents without permission password"
原因:文档是用打开密码载入的,此时只具备阅读权限。移除加密属于权限级操作,必须提供权限密码(也称所有者密码)才能完成。
解决:两种写法都可行——用权限密码载入后调用无参的 Decrypt(),或者保留打开密码载入、把权限密码交给 Decrypt:
// 写法一:用权限密码载入,再直接移除保护
doc.LoadFromFile(inputFileName, 'owner123');
doc.Decrypt();
// 写法二:用打开密码载入,把权限密码传给 Decrypt
doc.LoadFromFile(inputFileName, 'spire123');
doc.Decrypt('owner123');
加密算法该选哪一个
原因:PdfEncryptionKeySize 与 PdfEncryptionAlgorithm 列出了 RC4_40、RC4_128、AES_128、AES_256 等选项,但浏览器端的 WebAssembly 实现目前不支持 AES-256,把 EncryptionAlgorithm 设为 AES_256 会抛出 Cryptography_AlgorithmNotSupported。
解决:Web 端使用 AES_128;确实需要兼容只认 RC4 的旧阅读器时,可以改用 RC4_128:
// Web 端推荐:AES-128
policy.EncryptionAlgorithm = pdfModule.PdfEncryptionAlgorithm.AES_128;
// 需要兼容旧阅读器时:RC4-128
policy.EncryptionAlgorithm = pdfModule.PdfEncryptionAlgorithm.RC4_128;
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。









