JS localStorage 本地加密 过期时间的存储读写封装

76 min read
import { deCrypto, enCrypto } from '../crypto'

interface StorageData<T = any> {
  data: T
  expire: number | null
}

export function createLocalStorage(options?: { expire?: number | null; crypto?: boolean }) {
  const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7

  const { expire, crypto } = Object.assign(
    {
      expire: DEFAULT_CACHE_TIME,
      crypto: true,
    },
    options,
  )

  function set<T = any>(key: string, data: T) {
    const storageData: StorageData<T> = {
      data,
      expire: expire !== null ? new Date().getTime() + expire * 1000 : null,
    }

    const json = crypto ? enCrypto(storageData) : JSON.stringify(storageData)
    window.localStorage.setItem(key, json)
  }

  function get(key: string) {
    const json = window.localStorage.getItem(key)
    if (json) {
      let storageData: StorageData | null = null

      try {
        storageData = crypto ? deCrypto(json) : JSON.parse(json)
      }
      catch {
        // Prevent failure
      }

      if (storageData) {
        const { data, expire } = storageData
        if (expire === null || expire >= Date.now())
          return data
      }

      remove(key)
      return null
    }
  }

  function remove(key: string) {
    window.localStorage.removeItem(key)
  }

  function clear() {
    window.localStorage.clear()
  }

  return {
    set,
    get,
    remove,
    clear,
  }
}

export const ls = createLocalStorage()

export const ss = createLocalStorage({ expire: null, crypto: false })

import CryptoJS from 'crypto-js'

const CryptoSecret = '__CRYPTO_SECRET__'

export function enCrypto(data: any) {
  const str = JSON.stringify(data)
  return CryptoJS.AES.encrypt(str, CryptoSecret).toString()
}

export function deCrypto(data: string) {
  const bytes = CryptoJS.AES.decrypt(data, CryptoSecret)
  const str = bytes.toString(CryptoJS.enc.Utf8)

  if (str)
    return JSON.parse(str)

  return null
}

另一个更简单的例子

// 加密函数
function encrypt(data, key) {
  // TODO: 实现加密算法
  return data;
}

// 解密函数
function decrypt(data, key) {
  // TODO: 实现解密算法
  return data;
}

// 存储数据并设置过期时间(单位为秒)
function setWithExpiry(key, data, expiry) {
  const now = new Date();
  const item = {
    value: encrypt(data),
    expiry: now.getTime() + (expiry * 1000),
  };
  localStorage.setItem(key, JSON.stringify(item));
}

// 获取数据并检查过期时间
function getWithExpiry(key) {
  const itemStr = localStorage.getItem(key);
  if (!itemStr) {
    return null;
  }
  const item = JSON.parse(itemStr);
  const now = new Date();
  if (now.getTime() > item.expiry) {
    localStorage.removeItem(key);
    return null;
  }
  return decrypt(item.value);
}


使用方法如下:

// 存储数据并设置过期时间为 10 秒
setWithExpiry('myKey', { name: 'ChatGPT', age: 3 }, 10);

// 获取数据
const data = getWithExpiry('myKey');
console.log(data); // { name: 'ChatGPT', age: 3 }