要将加密和解密函数应用到 Pinia 状态中,我们需要创建一个 Pinia 插件,在状态持久化的过程中自动调用加密和解密方法。这样可以确保状态在存储时被加密,读取时被解密。
以下是完整的实现方案:
// plugins/piniaEncryption.js
import { encrypt, decrypt } from '../utils/crypto';
/**
* 创建Pinia加密存储插件
* @param {Object} options - 插件配置
* @param {string} [options.storage=localStorage] - 存储方式,可选localStorage或sessionStorage
* @param {Array<string>} [options.includeStores] - 仅加密指定的store,为空则加密所有
* @returns {Function} Pinia插件
*/
export function createEncryptionPlugin(options = {}) {
const {
storage = localStorage,
includeStores = []
} = options;
return function encryptionPlugin(context) {
const { store } = context;
// 如果指定了需要加密的store列表且当前store不在列表中,则不应用加密
if (includeStores.length > 0 && !includeStores.includes(store.$id)) {
return;
}
// 从存储中读取并解密数据
const loadEncryptedState = () => {
const key = `pinia_${store.$id}`;
const encryptedData = storage.getItem(key);
if (encryptedData) {
const decryptedData = decrypt(encryptedData);
if (decryptedData) {
store.$patch(decryptedData);
} else {
console.warn(`Failed to decrypt state for store: ${store.$id}`);
}
}
};
// 将数据加密并保存到存储
const saveEncryptedState = () => {
const key = `pinia_${store.$id}`;
// 排除内部属性,只保存状态数据
const state = { ...store.$state };
const encryptedData = encrypt(state);
storage.setItem(key, encryptedData);
};
// 初始化时加载解密后的状态
loadEncryptedState();
// 监听状态变化,自动加密保存
store.$subscribe((mutation, state) => {
saveEncryptedState();
}, { deep: true });
// 提供手动保存方法
store.$encryptSave = saveEncryptedState;
// 提供清除加密存储的方法
store.$clearEncryptedStorage = () => {
const key = `pinia_${store.$id}`;
storage.removeItem(key);
};
};
}
实现说明
这个方案通过 Pinia 插件机制,将加密和解密逻辑与状态管理无缝集成:
插件工作流程:
- 初始化时,从存储中读取加密数据并解密,然后应用到对应的 store
- 当状态发生变化时(通过
$subscribe
监听),自动将新状态加密后保存 - 提供手动加密保存(
$encryptSave
)和清除存储($clearEncryptedStorage
)的方法
使用方式:
- 创建 store 时无需特殊处理,插件会自动对状态进行加密存储
- 可以通过配置指定需要加密的 store(
includeStores
) - 支持切换 localStorage 和 sessionStorage 存储方式
在组件中使用:
```javascript
import { useUserStore } from '@/store/userStore';
export default {
setup() {
const userStore = useUserStore();
// 登录时设置状态,会自动加密存储
const handleLogin = () => {
userStore.login({
username: 'test',
token: 'secure-token'
});
};
// 手动触发保存(一般不需要,状态变化会自动保存)
const manualSave = () => {
userStore.$encryptSave();
};
// 清除存储的数据
const clearData = () => {
userStore.$clearEncryptedStorage();
};
return { handleLogin, manualSave, clearData };
}
};
```
通过这种方式,所有需要保护的 Pinia 状态都会在本地存储时自动加密,读取时自动解密,既保证了数据安全性,又不影响正常的状态管理逻辑。