前言
token+localStorage是目前从我的知识储备来看较好的一种认证存储方式,因为存储在cookie有XSS攻击的风险,存储在sessionStorage子标签不共享,标签页一删除就需要重新登录,用户体验十分不好。但是单纯地存储在localStorage里信息如果不手动删除就一直存在,所以决定设定时间让它消失并且在存储的时候处理一下加密,虽然保护不了什么但是至少让不懂的人一眼看不出,那就让我们来实现..
实现过期时间清除
思路
- 设置一个类,类属性有cache,以及time(过期时间)
- 设置get,set方法用于获取和设置缓存的内容
- get:先判断是否过期,如果过期就清除本地缓存;没有就返回缓存内的值
- 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;
}
}
}
实现加密存储
- 引入第三方的加密包crypto-js,我们使用AES加密解密
- 设置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};
优化
- 我们可以在settings文件夹里配置是否加密,开发环境下不加密,上线后就加密
- 设置存储的key的名称 【常量】存储一律按照这个key来存储/获取,例如window.localStorage.getItem(KEY);/window.localStorage.removeItem(KEY);这样我们就不需要去一个一个去翻看一个一个去修改
/** 设置本地存储是否加密 */
export const ifDecrypt = true;
/** 设置本地存储的key */
export const KEY = 'VUE3_TS_INFO';
梳理流程
- 登录成功调用Auth.js里的setAuth,将需要存储在本地的信息以及过期时间传入
- Auth.js就是一边存储到cache缓存里一边加密存储到localStorage里
- 那之后用于判断是否有权限或者是请求需要携带token那我们就先从cache里获取,判断是否过期,过期就清理,没过期就返回,
- 情况处理:
- 情况1 不刷新,从cache里获取token
- 过期 清除本地并返回空
- 不过期 返回值
- 情况2 刷新,从本地localStorage里获取
- 过期 清除本地返回空
- 不过其 返回值
- 情况1 不刷新,从cache里获取token
- 是的没错这里有一个很明显的缺陷,就是如果如果一直在线,但是token过期了,要清除就一定要在过期时间后访问一次需要带有token的请求才会触发获取cache,cache发现没有才会清除本地,欢迎交流~