自己封装【加密存储token】在localStorage带有过期时间

2,433 阅读3分钟

前言

token+localStorage是目前从我的知识储备来看较好的一种认证存储方式,因为存储在cookie有XSS攻击的风险存储在sessionStorage子标签不共享,标签页一删除就需要重新登录,用户体验十分不好。但是单纯地存储在localStorage里信息如果不手动删除就一直存在,所以决定设定时间让它消失并且在存储的时候处理一下加密,虽然保护不了什么但是至少让不懂的人一眼看不出,那就让我们来实现..

实现过期时间清除

思路

  1. 设置一个类,类属性有cache,以及time(过期时间)
  2. 设置get,set方法用于获取和设置缓存的内容
  3. get:先判断是否过期,如果过期就清除本地缓存;没有就返回缓存内的值
  4. set: cache[key] = value设置缓存
import { KEY } from '@/utils/setting';

export class Memory {
  /** 根据key来获取value */
  cache = {};
  alive;
  getCache(key = KEY) {
    return this.cache[key];
  }
  setCache(value, key = KEY) {
    this.cache[key] = value;
  }
  get() {
    const now = new Date().getTime();
    if (this.alive < now) {
      /** 删除指定key */
      window.localStorage.removeItem(KEY);
      /** 清空localStorage */
      window.localStorage.clear();
      return null;
    }
    return this.getCache();
  }
  set(value, time) {
    this.setCache(value);
    const now = new Date().getTime();
    /** alive单位为天 */
    this.alive = time;
    // this.alive = now + time * 1000;
  }
  resetCache(value) {
    const now = new Date().getTime();
    if (value.time > now) {
      this.setCache(value);
      this.alive = value.time;
      return true;
    } else {
      /** 删除指定key */
      window.localStorage.removeItem(KEY);
      /** 清空localStorage */
      window.localStorage.clear();
      return false;
    }
  }
}



实现加密存储

  1. 引入第三方的加密包crypto-js,我们使用AES加密解密
  2. 设置key,iv用于加密解密的前置条件
import {
  decryptByAES,
  encryptByAES,
} from '@/utils/cipher';
import {
  ifDecrypt,
  KEY,
} from '@/utils/setting';

/** 设置本地存储 */
export function setLocal(value) {
  const text = ifDecrypt
    ? encryptByAES(JSON.stringify(value))
    : JSON.stringify(value);
  window.localStorage[KEY] = text;
}

/** 获取本地存储 */
export function getLocal() {
  const text = window.localStorage.getItem(KEY);
  return ifDecrypt ? JSON.parse(decryptByAES(text)) : text;
}

/** 清除本地存储 */
export function clearLocal() {
  const text = window.localStorage.removeItem(KEY);
}


封装两者到Auth.js

import { store } from '@/store/index';
import { Memory } from '@/utils/cache';
import {
  clearLocal,
  getLocal,
  setLocal,
} from '@/utils/localStorage';

const localMemory = new Memory();
/** 设置认证 = 存储在缓存里 + 存储在本地 */
export const setAuth = (value) => {
  store.commit('setUserInfo', value.info);
  const now = new Date().getTime();
  const time = now + 1000 * 60 * 60 *24;
  // const time = 100*1000;
  localMemory.set(value, time);
  setLocal({token: value.token, info: value.info, time: time});
};

/** 获取认证 从缓存里 如果没有说明刷新 重新从本地获取 */
export const getAuth = () => {
  let token = localMemory.get();
  /** 没有token从本地获取 */
  if (!token) {
    const value = getLocal();
    if (!value) return null;
    /** 重新将本地的内容存储在缓存里 也要接收返回的结果 以防过期*/
    let result = localMemory.resetCache(value);
    if (result) {
      store.commit('setUserInfo', value.info);
    } else {
      return null;
    }
  }
  const value = localMemory.get();
  return value.token;
};

/** 清除认证 */
export const clearAuth = () => {
  clearLocal();
};
// export default {setAuth, getAuth};


优化

  1. 我们可以在settings文件夹里配置是否加密,开发环境下不加密,上线后就加密
  2. 设置存储的key的名称 【常量】存储一律按照这个key来存储/获取,例如window.localStorage.getItem(KEY);/window.localStorage.removeItem(KEY);这样我们就不需要去一个一个去翻看一个一个去修改
/** 设置本地存储是否加密 */
export const ifDecrypt = true;
/** 设置本地存储的key */
export const KEY = 'VUE3_TS_INFO';

梳理流程

  1. 登录成功调用Auth.js里的setAuth,将需要存储在本地的信息以及过期时间传入
  2. Auth.js就是一边存储到cache缓存里一边加密存储到localStorage里
  3. 那之后用于判断是否有权限或者是请求需要携带token那我们就先从cache里获取,判断是否过期,过期就清理,没过期就返回,
  4. 情况处理:
    1. 情况1 不刷新,从cache里获取token
      1. 过期 清除本地并返回空
      2. 不过期 返回值
    2. 情况2 刷新,从本地localStorage里获取
      1. 过期 清除本地返回空
      2. 不过其 返回值
  5. 是的没错这里有一个很明显的缺陷,就是如果如果一直在线,但是token过期了,要清除就一定要在过期时间后访问一次需要带有token的请求才会触发获取cache,cache发现没有才会清除本地,欢迎交流~