前言
最近接到个需求,需要将localStorage中的数据全部加密,但因为项目中使用localStorage的语法有localStorage['name'] = XXX 这种形式,导致重写setItem跟getItem的方法无法实现需求,所以借鉴vue响应式原理中的数据劫持思想,通过对localStorage的数据劫持,最终实现需求。话不多说,直接上代码。
实现
通过Object.defineProperty和proxy实现对localStorage的数据劫持
const setItem = function(key, value) {
return Reflect.set(storageProxy, key, value)
}
const getItem = function(key) {
return Reflect.get(storageProxy, key)
}
const removeItem = function(key) {
return Reflect.deleteProperty(storageProxy, key)
}
const clear = function() {
for (const key in storageProxy) {
Reflect.deleteProperty(storageProxy, key)
}
return false
}
const storageProxy = new Proxy(window.localStorage, {
set: function(ls, key, newValue) {
if (typeof key === 'string') {
return Reflect.set(ls, key, EncryptUtil.Encrypt(newValue, 'XXXXX'))//EncryptUtil.Encrypt(newValue, 'XXXXX')是数据加密
}
},
get: function(ls, prop) {
if (typeof prop === 'string' && prop === 'setItem') {
return setItem
} else if (prop === 'getItem') {
return getItem
} else if (prop === 'clear') {
return clear
} else if (prop === 'removeItem') {
return removeItem
}
const data = Reflect.get(ls, prop) ?? null
if (data) {
try {
// 兼容原本未加密的旧数据
const valueAfterDeciphering = EncryptUtil.Decrypt(data, 'XXXXX') //EncryptUtil.Decrypt(data, 'XXXXX')是数据解密
return valueAfterDeciphering || Reflect.get(ls, prop)
} catch (e) {
}
}
return Reflect.get(ls, prop) ?? null // 没值时返回undefined,进行JSON.parse解析会报错
}
})
Object.defineProperty(window, 'localStorage', {
configurable: true,
enumerable: true,
value: storageProxy
})