• token过期?页面如何实现无感刷新?


    我们为什么要无感刷新呢?

    我们都知道,后台返回的token是有时效性的,时间到了,你在交互后台的时候,后台会判断你的token是否过期(安全需要),如果过期了就会通过邪恶的手段逼迫你重新登陆!

    无感刷新是什么
    前面说到缩短token时间就会加大我们网站的安全性,但是缩短token用户就会生气了,所以为了让用户不生气,我们使用双token刷新、续期。

    双token是啥?access_token(短token—请求时带给后台的)和refresh_token(长token—用于刷新)

    活跃用户是啥? 我们这里判定access_token创建开始到2*access_token的时间为活跃(只要在这个时间段内,监听用户有操作就是活跃).

    使用双token
    用户第一次用账号密码登录,服务器返回3个参数: access_token、refresh_token和expires_in(短token过期时间,这里返回7200),时效长短不一样。短的access_token 时效过了之后,发送时效长的 refresh_token 重新获取一个短时效token,如果都过期,就需要重新登录了。

    refresh_token 就是用来刷新access_token 。
    活跃用户的access_token 过期了,用refresh_token获取新的access_token。

    步骤如下:

    1-token过期根据refresh_token获取新的token 重新获取数据

    2-创建一个新的axios实例 【使用request防止再次进入请求拦截和请求响应而进入死循环】

    3-根据请求相应的响应值 是不是401 是:说明token过期

    然后进行判断store中的 user :{token:'*****',refresh_token:'******'}中的 refresh_token和user对象是否存在 ,如果不存在说明之前没有登录过,直接去登录

    4-使用新创建的axios 实例对象 requestFreshToken 发送新的请求 headers中的口令携带的是 refresh_token

    5-获取token之后 将值重新赋值给user中的token

    6-将user重新存入store中

    7-重新获取刚才因为token失效而没有获取的数据 直接使用request 参数 来自error对象中【这里保存了之前token失效的请求数据】

    代码如下:

    1. // 导入axios, 后期会使用它创建出一个request实例, 用于发送请求
    2. import axios from "axios"
    3. // 导入store, 后期会使用它对vuex里面的user信息进行修改操作
    4. import store from "@/store"
    5. // 导入router, 后期会使用它进行路由跳转, 如果没有token和token过期直接跳转到login页面
    6. import router from "@/router"
    7. // jsonBig是一个包, 主要是对后端返回大数字的问题进行处理
    8. import jsonBig from "json-bigint"
    9. // 应该是移动端, 类似于element ui里面的this.$message.success等等
    10. import { Toast } from "vant"
    11. // 第一个axios实例是用于发送请求
    12. const request = axios.create({
    13. // axios提供了一个api, transformResponse
    14. // 它可以将后端的原数据进行自定义操作
    15. // 如果后端不进行处理, 那我们就可以使用下包的方式来进行手动的处理
    16. transformResponse: [
    17. function(data) {
    18. try {
    19. // 如果请求发送成功, 就将可能包含大数字的数据转换成一个BigNumber类型的对象, 它可以超出js的安全整数范围
    20. return jsonBig.parse(data)
    21. } catch (err) {
    22. // 如果转换失败,则包装为统一数据格式并返回
    23. return {
    24. data
    25. };
    26. }
    27. }
    28. ]
    29. });
    30. // 第二个axios实例用来当token失效的时候, refreshToken发送请求, 获取最新的token, 然后将错误的信息从新发送
    31. // 作用就是防止, 再次使用第一个axios实例发送请求, 请求拦截器死循环
    32. const requestFreshToken = axios.create()
    33. // 添加请求拦截器
    34. request.interceptors.request.use(
    35. // 成功的回调
    36. function(config) {
    37. // 如果user对象里面有token, 就说明是登录过的且token在失效期限内
    38. if (store.state.user) {
    39. // Bearer 是一个http身份验证的规则, 发送请求必须加上
    40. config.headers.Authorization = "Bearer " + store.state.user.token
    41. }
    42. return config
    43. },
    44. // 错误的回调
    45. function(error) {
    46. return Promise.reject(error)
    47. }
    48. )
    49. // 添加响应拦截器
    50. request.interceptors.response.use(
    51. // 响应拦截器的第一个回调函数, 成功走
    52. function(response) {
    53. console.log(response, 3)
    54. return response;
    55. },
    56. // 响应拦截器的第二个回到函数, 失败走
    57. async function(error) {
    58. console.log(error.response, 222)
    59. // 获取错误的response中的status状态
    60. const status = error.response.status
    61. // 如果浏览器返回的状态是为400, 那么就表示前端参数可能出现问题
    62. if (status == 400) {
    63. // 使用vant中的toast方法抛出一个提示
    64. Toast.file("请求参数错误")
    65. } else if (status == 401) { // 如果后端返回的状态为401, 就表示用户可能没有token, 或者token已经过期
    66. // 这里一共会出现三个情况:
    67. // 1. 用户没有登录
    68. // 2. 用户有登录, 发送请求发现token已经过去
    69. // 3. 出现异常
    70. // 调用vuex中state中存储的user信息
    71. const { user } = store.state;
    72. // 这里走的是没有登录的情况
    73. // 查看有没有存储refresh_token
    74. if (!user || !user.refresh_token) {
    75. // 如果没有就直接调换到login页面
    76. return router.push("/login")
    77. }
    78. // 这里走的是token已经失效的情况
    79. // 为什么需要try一下, 因为发送ajax可能会成功, 也可能会失败
    80. try {
    81. // 这里使用的requestFreshToken实例发送请求异步请求, 因为如果在使用request会陷入死循环
    82. const { data } = await requestFreshToken({
    83. method: "PUT",
    84. url: "/v1_0/authorizations",
    85. headers: {
    86. // 直接使用登录时, 存储的refresh_token发送新请求, 获取新的token
    87. // 无感刷新也就在于这里
    88. // 当浏览器发送请求, 请求拦截器发现token已经失效
    89. // 那么就需要使用到refresh_token来发送请求, 获取新的token
    90. // 服务器响应之后将新的token存储本地, 最后将失败的请求发送出去
    91. Authorization: "Bearer " + user.refresh_token
    92. }
    93. });
    94. // 将服务器返回的新token重新保存到user里面
    95. user.token = data.data.token
    96. // 注意, 想要修改state里面的数据, 必须通过mutations, 因为数据追踪的就知道是谁修改的
    97. store.commit("setUser", user)
    98. return request(error.response.config)
    99. } catch (error) {}
    100. // 出现异常直接返回登录页
    101. return router.push("/login")
    102. Toast.file("用户认证失败")
    103. } else if (status == 403) {
    104. // 客户端没有权限
    105. Toast.file("客户端没有权限")
    106. } else if (status == 405) {
    107. // 请求方法不支持
    108. Toast.file("请求方法不支持")
    109. }
    110. // 如果服务器返回的状态码, 以上if判断都不存在, 那么直接抛出错误
    111. return Promise.reject(error)
    112. }
    113. )
    114. // 最后导出request实例, 供其他组件发送ajax时使用
    115. export default request

  • 相关阅读:
    autojs(意图篇之startActivity)
    Debezium系列之:Debezium技术专栏第300篇系列文章之打通Debezium实时采集Oracle数据库数据到Kafka集群的技术
    Collectors.collectingAndThen()
    【STM32】TIM2的PWM:脉冲宽度调制
    Flink DataStream API
    LamdaUpdateWapper失效问题
    【ElementUI】el-table中复选框禁用处理
    20240307-2-前端开发校招面试问题整理HTML
    7.7亿参数,超越5400亿PaLM!UW谷歌提出「分步蒸馏」,只需80%训练数据|ACL 2023
    Python 专栏目录索引
  • 原文地址:https://blog.csdn.net/weixin_48524561/article/details/125513409