拦截/劫持localStorage

649 阅读1分钟

前言

最近接到个需求,需要将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
})