这里介绍对token的处理
问题1:token数据或者其他数据,存在vuex仓库中,刷新会丢失状态 。
问题2:数据只存在本地,数据变化了,相关的视图并不会更新。 Vuex 容器中的数据只是为了方便在其他任何地方能方便的获取登录状态数据, 但是页面刷新还是会丢失数据状态,所以我们还要把 数据进行持久化 以防止页面刷新丢失状态的问题。两种方式配合达到存储+响应式的功能。
前端持久化常见的方式:Cookie,localstorage本地存储
基本思路就是:
用户登录成功之后,把token保存到本地的localstorage或者cookie中,在vuex中也存一份
在vuex容器初始化的时候,优先使用本地存储的值
使用vuex管理token
在之前,我们在我们是在登录页面中发送的登录请求之后,获取到token,然后通过提交mutation的方式将token存到了vuex中,然后这里我们希望将登录token的异步操作,也封装成action,封装到vuex中,集中管理关于token操作。
vue封装action存token,我们在这里存俩份,一份存进vuex的user.js分支中的state里面,一份存进本地的cookie中或者localstorage里面都行
store/modules/user.js 中准备状态,用来存放获取到的token信息,创建设置状态的mutations方法以及异步actions方法

const state = {token: '' // token字符串}
const mutations = {// 保存token的方法setTokenFn(state, newToken) {// 获取到token的时候,设置给token的同时也让setToken存进cookie中state.token = newTokensetToken(newToken)},
}
const actions = {// 登录async login(context, loginForm) {const { data } = await reqLogin(loginForm)if (data.success) context.commit('setTokenFn', data.data)},
}
const getters = {}export default {namespaced: true,state,mutations,getters
}

在登录页面中调用

    handleLogin() {// 预校验this.$refs.loginForm.validate(async valid => {if (valid) {// 开启登录按钮的loadingthis.loading = truetry {// 发送请求await this.$store.dispatch('user/login', this.loginForm)console.log('请求成功')this.$router.push('/')} catch (error) {console.log(error)}// 无论成功还是失败都要把loading关闭this.loading = false}})
}

添加token的getters
为了更好的让其他模块和组件获取到token数据和其他类似公共的数据的值,我们可以把这些数据添加到getters里,便于将来访问。可能你会说为什么不都写在一个store文件里,这是为了各模块之间的独立,使代码更清晰,所以都抽离出来了,在store/index.js中统一进行了挂载。

store/getters.js

const getters = {sidebar: state => state.app.sidebar,device: state => state.app.device,token: state => state.user.token, // 把token提到getters中,方便调用name: state => state.user.userInfo.username, // 用户名字的映射staffPhoto: state => state.user.userInfo.staffPhoto
}
export default getters

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import app from './modules/app'
import settings from './modules/settings'
import user from './modules/user'
import permission from './modules/permission'Vue.use(Vuex)const store = new Vuex.Store({modules: {app,settings,user,permission},getters // 这里是把getters挂载到全局,更加方便,如果放在modules里面,则在使用的时候还要加模块名
})export default store

vuex持久化
刚刚在登录时,已经可以成功的将token存到vuex中,但是vuex刷新会丢失,所以我们需要结合web存储实现持久化。
我们可以使用localstorage或者cookie进行存储,然后在utils文件夹中新建auth.js或者storage.js或者cookie.js,意思就是本地存储的文件,把本地存储数据的方法写进去
utils/auth.js

import Cookies from 'js-cookie'const TokenKey = 'qm-token'
const ThemeKey = 'qm-theme'export function getToken() {return Cookies.get(TokenKey)
}export function setToken(token) {return Cookies.set(TokenKey, token)
}export function removeToken() {return Cookies.remove(TokenKey)
}export function getTheme() {return Cookies.get(ThemeKey)
}export function setTheme(Theme) {return Cookies.set(ThemeKey, Theme)
}export function removeTheme() {return Cookies.remove(ThemeKey)
}

store/user.js 把token信息改为getToken(),一进来先从本地拿

const state = {// 一进来优先从缓存中取token: getToken() // token字符串
}

在存token的时候,本地也存一份

const mutations = {// 设置tokensetToken(state, newToken) {state.token = newToken// 设置了 token 的同时, 同步到本地cookies中setToken(newToken)}
}

token过期的处理
没有绝对的安全, 所谓的安全处理, 就是提高攻击者攻击的难度, 对他造成了一定的麻烦, 我们这个网站就是安全的! 网站安全性就是高的! 所以: token 必须要有过期时间! 每隔一段时间, 必须有一个新的token, 旧的token失效。

token的过期问题 你登陆成功之后,接口会返回一个token值,这个值在后续请求时带上(就像是开门钥匙)。 但是,这个值一般会有有效期(具体是多长,是由后端决定),在我们的项目中,这个有效期是2小时。 如果,上午8点登陆成功,到了10:01分,则token就会失效,再去发请求时,就会报401错误。 思考:

token需要过期时间吗 ?

token即是获取受保护资源的凭证,当然必须有过期时间。否则一次登录便可永久使用,认证功能就失去了其意义。非但必须有个过期时间,而且过期时间还不能太长,

参考各个主流网站的token过期时间,一般1小时左右

token一旦过期, 一定要处理, 不处理, 用户没法进行一些需要授权页面的使用了

token过期该怎么办?

token过期,就要重新获取。

那么重新获取有两种方式,一是重复第一次获取token的过程(比如登录,扫描授权等) ,这样做的缺点是用户体验不好,每一小时强制登录一次几乎是无法忍受的。

那么还剩第二种方法,那就是主动去刷新token. 主动刷新token的凭证是refresh token,也是加密字符串,并且和token是相关联的。相比可以获取各种资源的token,refresh token的作用仅仅是获取新的token,因此其作用和安全性要求都大为降低,所以其过期时间也可以设置得长一些。

目标效果 - 保证每一小时, 都是一个不同的token

token:
作用:在访问一些接口时,需要传入token,就是它。
有效期:2小时。
refresh_token
作用: 当token的有效期过了之后,可以使用它去请求一个特殊接口(这个接口也是后端指定的,明确需要传入refresh_token),并返回一个新的token回来(有效期还是2小时),以替换过期的那个token。
有效期:14天。(最理想的情况下,一次登陆可以持续14天。)


对于 某次请求A 的响应,如果是401错误
有refresh_token,用refresh_token去请求回新的token
新token请求成功
更新本地token
再发一次请求A
新token请求失败
清空vuex中的token
携带请求地址,跳转到登陆页
没有refresh_token
清空vuex中的token
携带请求地址,跳转到登陆页

对于一个请求的响应 401, 要这么处理, 对于十个请求的响应 401, 也要这么处理,
我们可以统一将这个token过期处理放在响应拦截器中
请求拦截器: 所有的请求, 在真正被发送出去之前, 都会先经过请求拦截器 (可以携带token)
响应拦截器: 所有的响应, 在真正被(.then.catch await)处理之前, 都会先经过响应拦截器, 可以在这个响应拦截器中统一对响应做判断

响应拦截器处理token

1、没有 refresh_token 拦截到登录页, 清除无效的token
utils/request.js

// 添加响应拦截器
http.interceptors.response.use(function (response) {// 对响应数据做点什么 (成功响应) response 就是成功的响应 resreturn response
}, function (error) {// 对响应错误做点什么 (失败响应) 处理401错误// console.dir(error)if (error.response.status === 401) {console.log('token过期了, 一小时过去了, 需要通过refresh_token去刷新token')// 获取 refresh_token, 判断是否存在, 存在就去刷新tokenconst refreshToken = store.state.tokenInfo.refresh_tokenif (refreshToken) {console.log('存在refreshToken, 需要进行刷新token操作')} else {// 没有refreshToken, 直接去登录, 将来还能跳回来// router.currentRoute 指向当前路由信息对象 === 等价于之前页面中用的 this.$route// 清除本地token, 跳转登录 (无意义的本地token内容, 要清除)store.commit('user/removeToken')router.push({path: '/login',query: {backto: router.currentRoute.fullPath}})}}return Promise.reject(error)
})

2、提供清除token的mutation
因为不仅要清空本地的token,还要清空vuex的token信息

store/user.js

  mutations: {setTokenFn (state, data) {state.tokenInfo = dataconsole.log('存', data)setToken(data)const res = getToken()console.log('取', res)},// 移出tokenInfo的信息, 恢复成空对象removeToken (state) {state.tokenInfo = {}// 更新到本地, 本地可以清掉token信息removeToken()}},

3、如果有refresh_token,那就发送请求,刷新token
注意: 这边发请求, 不要用上面二次处理好的request实例, 用它会自动在请求前帮你携带token(会覆盖你的refresh_token),要用原生的axios
注意:刷新完token,拿到最新的token并存好之后,应该重新发送刚刚的请求,做到让用户无感知

utils/request.js

const refreshToken = store.state.user.tokenInfo.refresh_token
if (refreshToken) {console.log('存在refreshToken, 需要进行刷新token操作')// (1) 发送请求, 进行刷新token操作, 获取新的token// 注意: 这边发请求, 不用request实例, 用它会自动在请求前帮你携带token(会覆盖你的refresh_token)// 这边, 直接用 axios 发送请求const res = await axios({method: 'put',url: 'http://toutiao.itheima.net/v1_0/authorizations',// 请求头中携带refresh_token信息headers: {Authorization: `Bearer ${refreshToken}`}})const newToken = res.data.data.token// (2) 将新token更新到vuex中store.commit('user/setTokenInfo', {refresh_token: refreshToken,token: newToken})
}

4、refresh_token也过期了
那就是真正的用户过期了,直接重复路由守卫里面的操作,清除掉本地token信息,带着目标路径前往login页面,登录完之后返回刚刚要前往的目标页面。
额,发现文章顺序写错了,这里提一下路由守卫里做了什么事,在07里面有。就是用户在进入白名单页面时,比如说首页或者其他不需要个人信息页面时,是不需要登录的,如果在没有登录的情况下,想要进入类似于个人中心,会员中心这种页面时,那么就需要让用户去登录页面登录一下,登录完成之后再返回刚刚要去的个人中心页面,这时候就是在路由跳转的时候,带上刚刚页面的路由路径,可以在登录完成之后原路返回。

// 添加请求拦截器
request.interceptors.request.use(function (config) {// 在发送请求之前做些什么const token = store.state.user.tokenInfo.tokenconsole.log(token)if (token) {config.headers.Authorization = `Bearer ${token}`}return config
}, function (error) {// 对请求错误做些什么console.log(error)return Promise.reject(error)
})// 添加响应拦截器
request.interceptors.response.use(function (response) {// 对响应数据做点什么return response
}, async function (error) {// 对响应错误做点什么// 对响应错误做点什么 (失败响应) 处理401错误// console.dir(error)if (error.response.status === 401) {console.log('token过期了, 一小时过去了, 需要通过refresh_token去刷新token')// 获取 refresh_token, 判断是否存在, 存在就去刷新tokenconst refreshToken = store.state.user.tokenInfo.refresh_tokenconsole.log(refreshToken)if (refreshToken) {try {console.log('存在refreshToken, 需要进行刷新token操作')// (1) 发送请求, 进行刷新token操作, 获取新的token// 注意: 这边发请求, 不用request实例, 用它会自动在请求前帮你携带token(会覆盖你的refresh_token)// 这边, 直接用 axios 发送请求const res = await axios({method: 'put',url: 'http://toutiao.itheima.net/v1_0/authorizations',// 请求头中携带refresh_token信息headers: {Authorization: `Bearer ${refreshToken}`}})const newToken = res.data.data.token// (2) 将新token更新到vuex中store.commit('user/setTokenFn', {refresh_token: refreshToken,token: newToken})console.log('>>>>>>>>>>>>>>>>>>>.', error.config)// 刷新token后,应该重新发送刚才的请求,让用户刷新token无感知return request(error.config)} catch (error) {console.log('使用refresh_token获取新token失败')// 清除本地token跳转路由store.commit('user/removeTokenInfo')// 路由跳转, 进入登录页router.push({path: '/login',query: {backto: router.currentRoute.fullPath}})}} else {// 没有refreshToken, 直接去登录, 将来还能跳回来// router.currentRoute 指向当前路由信息对象 === 等价于之前页面中用的 this.$route// 清除本地token, 跳转登录 (无意义的本地token内容, 要清除)store.commit('user/removeToken')router.push({path: '/login',query: {backto: router.currentRoute.fullPath}})}}return Promise.reject(error)
})

用vuex对token/refresh_token 进行管理以及处理token过期问题相关推荐

  1. 基于token的登录管理(多设备登录、单设备登录)

    详情参见: https://gitee.com/xxssyyyyssxx/token 不管是客户端接口还是网页H5接口,一般我们都需要登录验证,即要求所有的接口访问都必须在登录之后,以确认身份,防止非 ...

  2. cookie session token区别_cookie、session与token的真正区别

    发展史 1.很久很久以前,Web 基本上就是文档的浏览而已, 既然是浏览,作为服务器, 不需要记录谁在某一段时间里都浏览了什么文档,每次请求都是一个新的HTTP协议, 就是请求加响应, 尤其是我不用记 ...

  3. 叶开|Token的10大设计模式及Token金融与治理(长篇干货)

    作者:叶开 Token经济系统设计方面的先行者. 矩阵数字经济智库合伙人,林达控股(1041HK)执行董事,中农普惠金服董事合伙人,南京大学兼职教授.专注于传统产业升级.产业金融和区块链,著有< ...

  4. springboot +vue实现token登录1之vue的token存储

    0.写在前面 在前后端完全分离的情况下,Vue项目中实现token验证大致思路如下: 1.第一次登录的时候,前端调后端的登陆接口,发送用户名和密码 2.后端收到请求,验证用户名和密码,验证成功,就给前 ...

  5. 又一方案实现发行Token的功能,BCH平台Token即将迎来大爆发

    前段时间BCH社区中提出了多种智能合约方案,如虫洞Wormhole,Bitprim的Keoken,Cryptonize.it推出的彩色币协议,另一个是由Jonald Fyookball(Electro ...

  6. token干什么用_浅谈Token理解运用

    周末没带电脑,闲着也是闲着,出来分享一点东西,也当自己学习和巩固了. 今天分享一下Token的理解,首先Token的定义是什么? 概念 Token被翻译成为('令牌','标记')在计算机中的含义也差不 ...

  7. jwt token注销_详解JWT token心得与使用实例

    本文你能学到什么? token的组成 token串的生成流程. token在客户端与服务器端的交互流程 Token的优点和思考 参考代码:核心代码使用参考,不是全部代码 JWT token的组成 头部 ...

  8. php微信公众号测试号token配置失败,微信公众号Token配置失败解决办法

    前言 今天生病在家,由于我的微信公众号被投诉了,因此影视站接口被迫关闭,于是就想着给大家分享 APP,于是就用了下微信的自动回复, 想着能否把这个自动回复对接到 MIPCMS 上,于是就开干.但是微信 ...

  9. android token机制_Android之window机制token验证

    前言 很高兴遇见你~ 欢迎阅读我的文章 这篇文章讲解关于window token的问题,同时也是Context机制和Window机制这两篇文章的一个补充.如果你对Android的Window机制和Co ...

最新文章

  1. nextcloud网站不安全_教你搭建私有云盘,简单快速,完全傻瓜式!不限速,永久有效!...
  2. QT的QSqlQueryModel类的使用
  3. *args 和**kwargs 的理解以及 函数的参数的总结
  4. CentOS7 安装NodeJS
  5. 如何在 Linux 中使用 AppImage
  6. 八、接口中的默认方法与静态方法
  7. Java、JSP网上音像管理系统的设计与实现
  8. siege 测试post_使用Siege进行Web App性能测试:计划,测试,学习
  9. SQL Server常用函数整理
  10. python-图像边缘化处理
  11. C盘Temp文件夹的内容可以删掉
  12. 微信公众平台服务号配置JS接口安全域名
  13. Gamemaker studio2经验(2)——TCP联机
  14. 64位Windows 8 运行Trial-Reset,但是提示缺少“MSCOMCTL.OCX”的解决方法
  15. 初学python制作二维码以及最新感悟
  16. 数据分析-建立回归模型的流程
  17. UI自动化+python元素识别
  18. 欧姆龙EtherCAT通讯及OPC UA功能硫化机程序(plc程序+触摸屏程序)
  19. android 音量调节不起作用,Android开发之调整手机音量
  20. Python编写masscan+nmap的主机和端口信息收集工具

热门文章

  1. C#使用winform做一个开关小游戏
  2. 递归问题:Fibonacci 数列 排列问题
  3. Linux通过命令行操作Mysql
  4. 淘宝镜像已经更改成Ruby China
  5. EasyUEFI 管理配置 Windows EFI 启动项
  6. Openfiler的安装+ISCSI和NFS共享存储的基础配置
  7. Preference类中xml里属性的用法和介绍记录
  8. 密码锁 java接口_指纹门锁的USB接口怎么用 USB应急充电接口使用方法
  9. NeuroImage:多模态超扫描揭示母与子在身体和心灵上的同步
  10. 编译原理——词法分析器的设计