Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

基于token的刷新方案及实现 #13

Open
xchunzhao opened this issue Dec 15, 2020 · 0 comments
Open

基于token的刷新方案及实现 #13

xchunzhao opened this issue Dec 15, 2020 · 0 comments

Comments

@xchunzhao
Copy link
Owner

背景

移动端场景下,鉴权的方案是基于 token。至于该 token 生成方案,在此不做具体介绍。本文主要介绍处理 token 过期时的实现方案。

需求梳理

token过期,我们需要在过期时刷新该token

而我们需要注意的是:

  • token刷新的时机
  • 并发场景下,刷新token如何保证不重复刷新
  • token刷新完,需要重新执行之前的请求

方案

  • 基于token过期时间的刷新

简言之,根据token约定的有效时间,每次用到token之前查看token是否超过有效时间,在有效期内的话就直接使用,否则需要刷新

这种刷新方案存在一个问题,后端可能由于某种原因保存的session丢失,或者客户端保存的有效时间丢失。

  • 拦截请求,针对后端提示token过期进行刷新

根据之前梳理的需求,一一解答

1、 刷新时机

后端响应到达客户端时,根据具体的状态码判断是否过期,即是否需要刷新

2、 并发保证不重复刷新

使用锁机制,在刷新 token 过程中,该锁处于占用状态,即其他请求到达时,不会执行刷新。刷新完,该锁释放。

3、 刷新完,之前的请求重新执行

通过队列的方式保存之前的请求,待token刷新完,再执行队列中的请求。

具体实现

// 假设存在请求方法为request, 可替换成任意request库

// 刷新token的锁
let isRefreshToken = false
// 保存原请求的队列
let subscribers = []
// token刷新完,队列中的请求执行
const onTokenRefreshed = token => {
  subscribers = subscribers.forEach(callback => callback(token))
  subscribers = []
}
// 向队列中添加原请求
const addSubscribers = callback => subscribers.push(callback)


request(url, options)
  .then(response => {
      // 假设token过期时的code为401
      if(response.statusCode === 401) {
        // 未占用锁
        if(!isRefreshToken) {
          // 刷新前占用锁
          isRefreshToken = true
          const { token } = await refreshToken()
          // 刷新完释放锁
          isRefreshToken = false
          // 执行队列中的原请求
          onTokenRefreshed(token)
        }
        
        // 原请求加入缓冲队列
        const retryOriginRequest = new Promise(resolve => {
          addSubscribers(token => {
            resolve(request(url, { ...options, token }))
          })
        })
        return retryOriginRequest
      }
  })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant