mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-27 14:47:28 +08:00
feat: the cache can be configured to be encrypted
This commit is contained in:
78
src/utils/cache/cookie.ts
vendored
Normal file
78
src/utils/cache/cookie.ts
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
import { DEFAULT_CACHE_TIME } from '../../settings/encryptionSetting';
|
||||
import { getStorageShortName } from '/@/utils/helper/envHelper';
|
||||
import { cacheCipher } from '/@/settings/encryptionSetting';
|
||||
import Encryption from '/@/utils/encryption/aesEncryption';
|
||||
|
||||
export default class WebCookie {
|
||||
private encryption: Encryption;
|
||||
private hasEncrypt: boolean;
|
||||
|
||||
constructor(hasEncrypt = true, key = cacheCipher.key, iv = cacheCipher.iv) {
|
||||
const encryption = new Encryption({ key, iv });
|
||||
this.encryption = encryption;
|
||||
this.hasEncrypt = hasEncrypt;
|
||||
}
|
||||
|
||||
private getKey(key: string) {
|
||||
return `${getStorageShortName()}${key}`.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add cookie
|
||||
* @param name cookie key
|
||||
* @param value cookie value
|
||||
* @param expire
|
||||
* If the expiration time is not set, the default management browser will automatically delete
|
||||
* e.g:
|
||||
* cookieData.set('name','value',)
|
||||
*/
|
||||
setCookie(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
|
||||
value = this.hasEncrypt ? this.encryption.encryptByAES(JSON.stringify(value)) : value;
|
||||
document.cookie = this.getKey(key) + '=' + value + '; Max-Age=' + expire;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cook value according to the key
|
||||
* @param key cookie key
|
||||
*/
|
||||
getCookie(key: string) {
|
||||
const arr = document.cookie.split('; ');
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const arr2 = arr[i].split('=');
|
||||
if (arr2[0] === this.getKey(key)) {
|
||||
let message: any = null;
|
||||
const str = arr2[1];
|
||||
if (this.hasEncrypt && str) {
|
||||
message = this.encryption.decryptByAES(str);
|
||||
try {
|
||||
return JSON.parse(message);
|
||||
} catch (e) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete cookie based on cookie key
|
||||
* @param key cookie key
|
||||
*/
|
||||
removeCookie(key: string) {
|
||||
this.setCookie(key, 1, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* clear cookie
|
||||
*/
|
||||
clearCookie(): void {
|
||||
const keys = document.cookie.match(/[^ =;]+(?==)/g);
|
||||
if (keys) {
|
||||
for (let i = keys.length; i--; ) {
|
||||
document.cookie = keys[i] + '=0;expires=' + new Date(0).toUTCString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,17 +1,20 @@
|
||||
import { getStorageShortName } from '/@/utils/helper/envHelper';
|
||||
import { createStorage as create } from './Storage';
|
||||
|
||||
// debug模式下不加密
|
||||
import { createStorage as create } from './storageCache';
|
||||
import { enableStorageEncryption } from '/@/settings/encryptionSetting';
|
||||
|
||||
const createOptions = (storage = sessionStorage) => {
|
||||
return {
|
||||
// No encryption in debug mode
|
||||
hasEncrypt: enableStorageEncryption,
|
||||
storage,
|
||||
prefixKey: getStorageShortName(),
|
||||
};
|
||||
};
|
||||
|
||||
export const WebStorage = create(createOptions());
|
||||
|
||||
export const createStorage = (storage: Storage = sessionStorage) => {
|
||||
return create(createOptions(storage))!;
|
||||
};
|
||||
|
||||
export default WebStorage;
|
108
src/utils/cache/storageCache.ts
vendored
Normal file
108
src/utils/cache/storageCache.ts
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
import { DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting';
|
||||
import { cacheCipher } from '/@/settings/encryptionSetting';
|
||||
import Encryption, { EncryptionParams } from '/@/utils/encryption/aesEncryption';
|
||||
|
||||
export interface CreateStorageParams extends EncryptionParams {
|
||||
storage: Storage;
|
||||
|
||||
hasEncrypt: boolean;
|
||||
}
|
||||
export const createStorage = ({
|
||||
prefixKey = '',
|
||||
storage = sessionStorage,
|
||||
key = cacheCipher.key,
|
||||
iv = cacheCipher.iv,
|
||||
hasEncrypt = true,
|
||||
} = {}) => {
|
||||
if (hasEncrypt && [key.length, iv.length].some((item) => item !== 16)) {
|
||||
throw new Error('When hasEncrypt is true, the key or iv must be 16 bits!');
|
||||
}
|
||||
|
||||
const encryption = new Encryption({ key, iv });
|
||||
|
||||
/**
|
||||
*Cache class
|
||||
*Construction parameters can be passed into sessionStorage, localStorage,
|
||||
* @class Cache
|
||||
* @example
|
||||
*/
|
||||
const WebStorage = class WebStorage {
|
||||
private storage: Storage;
|
||||
private prefixKey?: string;
|
||||
private encryption: Encryption;
|
||||
private hasEncrypt: boolean;
|
||||
/**
|
||||
*
|
||||
* @param {*} storage
|
||||
*/
|
||||
constructor() {
|
||||
this.storage = storage;
|
||||
this.prefixKey = prefixKey;
|
||||
this.encryption = encryption;
|
||||
this.hasEncrypt = hasEncrypt;
|
||||
}
|
||||
|
||||
private getKey(key: string) {
|
||||
return `${this.prefixKey}${key}`.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Set cache
|
||||
* @param {string} key
|
||||
* @param {*} value
|
||||
* @expire Expiration time in seconds
|
||||
* @memberof Cache
|
||||
*/
|
||||
set(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
|
||||
const stringData = JSON.stringify({
|
||||
value,
|
||||
expire: expire !== null ? new Date().getTime() + expire * 1000 : null,
|
||||
});
|
||||
const stringifyValue = this.hasEncrypt
|
||||
? this.encryption.encryptByAES(stringData)
|
||||
: stringData;
|
||||
this.storage.setItem(this.getKey(key), stringifyValue);
|
||||
}
|
||||
|
||||
/**
|
||||
*Read cache
|
||||
* @param {string} key
|
||||
* @memberof Cache
|
||||
*/
|
||||
get(key: string, def: any = null): any {
|
||||
const item = this.storage.getItem(this.getKey(key));
|
||||
if (item) {
|
||||
try {
|
||||
const decItem = this.hasEncrypt ? this.encryption.decryptByAES(item) : item;
|
||||
const data = JSON.parse(decItem);
|
||||
const { value, expire } = data;
|
||||
if (expire === null || expire >= new Date().getTime()) {
|
||||
return value;
|
||||
}
|
||||
this.remove(this.getKey(key));
|
||||
} catch (e) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete cache based on key
|
||||
* @param {string} key
|
||||
* @memberof Cache
|
||||
*/
|
||||
remove(key: string) {
|
||||
this.storage.removeItem(this.getKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all caches of this instance
|
||||
*/
|
||||
clear(): void {
|
||||
this.storage.clear();
|
||||
}
|
||||
};
|
||||
return new WebStorage();
|
||||
};
|
35
src/utils/encryption/aesEncryption.ts
Normal file
35
src/utils/encryption/aesEncryption.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import CryptoES from 'crypto-es';
|
||||
export interface EncryptionParams {
|
||||
key: string;
|
||||
iv: string;
|
||||
}
|
||||
export class Encryption {
|
||||
private key;
|
||||
|
||||
private iv;
|
||||
|
||||
constructor(opt: EncryptionParams) {
|
||||
const { key, iv } = opt;
|
||||
this.key = CryptoES.enc.Utf8.parse(key);
|
||||
this.iv = CryptoES.enc.Utf8.parse(iv);
|
||||
}
|
||||
|
||||
get getOpt(): CryptoES.lib.CipherCfg {
|
||||
return {
|
||||
mode: CryptoES.mode.CBC as any,
|
||||
padding: CryptoES.pad.Pkcs7,
|
||||
iv: this.iv,
|
||||
};
|
||||
}
|
||||
|
||||
encryptByAES(str: string) {
|
||||
const encrypted = CryptoES.AES.encrypt(str, this.key, this.getOpt);
|
||||
return encrypted.toString();
|
||||
}
|
||||
|
||||
decryptByAES(str: string) {
|
||||
const decrypted = CryptoES.AES.decrypt(str, this.key, this.getOpt);
|
||||
return decrypted.toString(CryptoES.enc.Utf8);
|
||||
}
|
||||
}
|
||||
export default Encryption;
|
@@ -1,4 +1,4 @@
|
||||
import { dataURLtoBlob, urlToBase64 } from './base64';
|
||||
import { dataURLtoBlob, urlToBase64 } from './base64Conver';
|
||||
|
||||
/**
|
||||
* Download online pictures
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { createStorage } from '/@/utils/storage';
|
||||
import { createStorage } from '/@/utils/cache';
|
||||
import { isIeFn } from '/@/utils/browser';
|
||||
|
||||
import { BASE_LOCAL_CACHE_KEY, BASE_SESSION_CACHE_KEY } from '/@/enums/cacheEnum';
|
||||
|
@@ -1,138 +0,0 @@
|
||||
import { DEFAULT_CACHE_TIME } from '/@/settings/cipherSetting';
|
||||
|
||||
// import { EncryptionParams } from '/@/utils/cipher/aesEncryption';
|
||||
export interface CreateStorageParams {
|
||||
storage: Storage;
|
||||
hasEncrypt: boolean;
|
||||
}
|
||||
export const createStorage = ({ prefixKey = '', storage = sessionStorage } = {}) => {
|
||||
/**
|
||||
*缓存类
|
||||
*构造参数可以传入 sessionStorage,localStorage,
|
||||
* @class Cache
|
||||
* @example
|
||||
*/
|
||||
const WebStorage = class WebStorage {
|
||||
private storage: Storage;
|
||||
private prefixKey?: string;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} storage
|
||||
*/
|
||||
constructor() {
|
||||
this.storage = storage;
|
||||
this.prefixKey = prefixKey;
|
||||
}
|
||||
|
||||
private getKey(key: string) {
|
||||
return `${this.prefixKey}${key}`.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 设置缓存
|
||||
* @param {string} key 缓存键
|
||||
* @param {*} value 缓存值
|
||||
* @expire 过期时间 单位秒
|
||||
* @memberof Cache
|
||||
*/
|
||||
set(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
|
||||
const stringData = JSON.stringify({
|
||||
value,
|
||||
expire: expire !== null ? new Date().getTime() + expire * 1000 : null,
|
||||
});
|
||||
this.storage.setItem(this.getKey(key), stringData);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*读取缓存
|
||||
* @param {string} key 缓存键
|
||||
* @returns 缓存值
|
||||
* @memberof Cache
|
||||
*/
|
||||
get(key: string, def: any = null): any {
|
||||
const item = this.storage.getItem(this.getKey(key));
|
||||
if (item) {
|
||||
try {
|
||||
const data = JSON.parse(item);
|
||||
const { value, expire } = data;
|
||||
if (expire === null || expire >= new Date().getTime()) {
|
||||
return value;
|
||||
}
|
||||
this.remove(this.getKey(key));
|
||||
} catch (e) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*删除缓存
|
||||
* @param {string} key 缓存键
|
||||
* @memberof Cache
|
||||
*/
|
||||
remove(key: string) {
|
||||
this.storage.removeItem(this.getKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*删除该实例所有缓存
|
||||
* @memberof Cache
|
||||
*/
|
||||
clear(): void {
|
||||
this.storage.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加cookie
|
||||
* @param name cookie名字
|
||||
* @param value cookie内容
|
||||
* @param expire
|
||||
* 如果过期时间未设置,默认管理浏览器自动删除
|
||||
* 例子:
|
||||
* cookieData.set('name','value',)
|
||||
*/
|
||||
setCookie(name: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
|
||||
document.cookie = this.getKey(name) + '=' + value + '; Max-Age=' + expire;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名字获取cooki值
|
||||
* @param name cookie名
|
||||
* @returns {*} cookie值
|
||||
*/
|
||||
getCookie(name: string) {
|
||||
const arr = document.cookie.split('; ');
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const arr2 = arr[i].split('=');
|
||||
if (arr2[0] === this.getKey(name)) {
|
||||
return arr2[1];
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据cookie名字删除cookie
|
||||
* @param name cookie名字
|
||||
*/
|
||||
removeCookie(key: string) {
|
||||
this.setCookie(key, 1, -1);
|
||||
}
|
||||
|
||||
clearCookie(): void {
|
||||
const keys = document.cookie.match(/[^ =;]+(?==)/g);
|
||||
if (keys) {
|
||||
for (let i = keys.length; i--; ) {
|
||||
document.cookie = keys[i] + '=0;expires=' + new Date(0).toUTCString();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return new WebStorage();
|
||||
};
|
Reference in New Issue
Block a user