Pinia 本身不提供加密能力,敏感全局状态持久化需在序列化环节主动介入:写入前加密、读取后解密,对业务 Store 透明;中低敏数据推荐 crypto-js + AES-CBC,高敏数据须用 Web Crypto API + AES-GCM;应分级隔离、字段级加密,通过插件在 $subscribe 或持久化钩子中统一处理,并注意 SSR 和跨端兼容性。

Pinia 本身不提供加密能力,敏感全局状态的持久化必须在序列化环节主动介入加密,核心原则是:写入前加密、读取后解密,且对业务 Store 完全透明。
选对加密方案,匹配安全等级
中低敏感数据(如用户偏好、表单草稿)推荐用 crypto-js + AES-CBC:安装 npm install crypto-js,密钥用 16/24/32 字节 UTF-8 字符串(例如 'a0b1c2d3e4f5g6h7'),务必避免硬编码,生产环境应从环境变量或登录后动态获取;启用 IV(初始向量)和 PKCS7 填充,防止重放攻击。
高敏感数据(如 access_token、refresh_token、身份证号)应使用浏览器原生 Web Crypto API + AES-GCM:调用 window.crypto.subtle,支持认证加密(AEAD),可验证数据完整性;密钥需通过 importKey() 导入,IV 每次加密随机生成,并与密文 Base64 拼接存储;注意 IE 不支持,但 Chrome 91+、Firefox 88+、Safari 15.4+ 均已兼容。
只加密该加密的字段,不做无差别全量加密
不是所有状态都需要加密。建议分级隔离:
- 抽离高敏字段到专用 Store(如
useAuthStore),仅对该 Store 启用加密插件 - 中低敏数据(主题色、语言、菜单折叠状态)可用
pinia-plugin-persistedstate配合普通 localStorage - 临时数据(搜索关键词、未提交表单内容)存 sessionStorage 或干脆不持久化
避免直接对整个 store.$state 加密——先做字段过滤,再加密精简后的对象。
插件层统一处理加解密逻辑
加密必须通过 Pinia 插件机制实现,在 $subscribe 或持久化插件的序列化/反序列化钩子中注入:
- 初始化时读取存储值,尝试解密;失败则回退为空对象或默认值
- 状态变更后立即加密并写入 localStorage(或跨平台适配的存储 API)
- 若用
pinia-plugin-persistedstate,需自定义serializer选项,覆盖serialize和deserialize方法 - 在 Vue Vben Admin 等框架中,通常已在
src/store/plugin/persist.ts封装好加密持久化逻辑,只需在 Store 中声明persist: true并指定加密策略
注意 SSR 和跨平台兼容性
服务端渲染时,window 和加密 API 不可用,需判断运行环境:
- 加密逻辑只在客户端执行,SSR 阶段跳过或返回空状态
- uni-app 等跨端场景,优先选用
pinia-plugin-persist-uni,它会根据process.env.UNI_PLATFORM自动切换 H5 的 localStorage、小程序的uni.setStorageSync等适配器 - 避免在加密流程中使用依赖 DOM 或全局对象的代码,确保可被服务端安全忽略











