如何解决token过期问题,怎么处理?

前端 潘老师 5个月前 (12-05) 131 ℃ (0)

本文主要讲解关于如何解决token过期的问题,学习token过期了怎么处理相关内容,让我们来一起学习下吧!

token过期了怎么办?一般做法是重复第一次获取token的过程(比如登录,扫描授权等) ,这样做的缺点是用户体验不好,每一小时强制登录一次几乎是无法忍受的。那应该怎么办呢?其实这是一个老生常谈的问题,但是最近发现很多人并不清楚,所以今天就一次讲清这个问题!

token 过期处理

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

token 过期问题

目标: 了解token过期问题的存在, 学习token过期的解决思路

现象:

你登陆成功之后,接口会返回一个token值,这个值在后续请求时带上(就像是开门钥匙)。

但是,这个值一般会有有效期(具体是多长,是由后端决定),在我们的项目中,这个有效期是2小时。

如果,上午8点登陆成功,到了10:01分,则token就会失效,再去发请求时,就会报401错误。

思考:

  1. token需要过期时间吗 ?

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

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

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

  2. token过期该怎么办?

    token过期,就要重新获取。

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

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

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

第一次请求 9:00 用的是 token1第二次请求 12:00 用的是 token2

当用户登陆成功之后,返回的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

目标: 通过 axios 响应拦截器来处理 token 过期的问题

  1. 没有 refresh_token 拦截到登录页, 清除无效的token

测试: {“token”:”123.123.123″}

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

提供清除token的mutation

// 移出tokenInfo的信息, 恢复成空对象
removeToken (state) {
  state.tokenInfo = {}
  // 更新到本地, 本地可以清掉token信息
  removeToken()
},
  1. 有 refresh_token 发送请求, 刷新token

测试操作: 将 token 修改成 xyz, 模拟 token 过期, 而有 refresh_token 发现401, 会自动帮你刷新token

{"refresh_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MDYzNTcyODcsInVzZXJfaWQiOjExMDI0OTA1MjI4Mjk3MTc1MDQsInJlZnJlc2giOnRydWV9.2A81gpjxP_wWOjclv0fzSh1wzNm6lNy0iXM5G5l7TQ4","token":"xyz"}

const refreshToken = store.state.tokenInfo.refresh_token
if (refreshToken) {
  console.log('存在refreshToken, 需要进行刷新token操作')
  // (1) 发送请求, 进行刷新token操作, 获取新的token
  // 注意: 这边发请求, 不用http实例, 用它会自动在请求前帮你携带token(会覆盖你的refresh_token)
  // 这边, 直接用 axios 发送请求
  const res = await axios({
    method: 'put',
    url: 'http://ttapi.research.itcast.cn/app/v1_0/authorizations',
    // 请求头中携带refresh_token信息
    headers: {
      Authorization: `Bearer ${refreshToken}`
    }
  })
  const newToken = res.data.data.token
  // (2) 将新token更新到vuex中
  store.commit('setTokenInfo', {
    refresh_token: refreshToken,
    token: newToken
  })
} 
  1. 刷新token后, 应该重新发送刚才的请求 (让用户刷新token无感知)
return http(error.config)
  1. 那万一 refresh_token 也过期了, 是真正的用户登录过期了 (一定要让用户重新登录的)

测试: {“refresh_token”:”123.123″,”token”:”123.123.123″} 修改后, 修改的是本地, 记得刷新一下

从哪拦走的, 就回到哪去

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

注意点:

  1. 响应拦截器要加在axios实例 http 上。
  2. 用refresh_token请求新token时,要用axios,不要用实例 http (需要: 手动用 refresh_token 请求)
  3. 得到新token之后,再发请求时,要用 http 实例 (用token请求)
  4. 过期的 token 可以用 refresh_token 再次更新获取新token, 但是过期的 refresh_token 就应该从清除了

以上就是关于如何解决token过期的问题,学习token过期了怎么处理相关的全部内容,希望对你有帮助。欢迎持续关注潘子夜个人博客(www.panziye.com),学习愉快哦!


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/front/12119.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】