何谓Token无感知刷新以及实现思路

310 阅读2分钟

在前端实现无感知刷新令牌(Token Refresh)是为了在用户访问应用程序期间,确保他们的身份认证令牌(通常是JWT)不会过期,以允许持续的用户会话而不需要重新登录, 一般前后端的交互是这样: 用户在前端登陆, 服务器返回两个token, 一个验证Token, 一个刷新Token, 平时请求携带的都是验证Token ,如果请求返回告知需要刷新则前端再做处理

以下是实现前端无感知刷新令牌的一般步骤和示例代码

身份认证令牌(Token)和刷新令牌(Refresh Token)

通常,身份认证令牌用于对用户进行身份验证和授权,而刷新令牌用于在身份认证令牌过期时获取新的身份认证令牌

检查到令牌过期

前后端一般会约定一个 code , 当请求返回该code时, 则代表身份认证令牌过期,在前端应用程序中,当该请求发送到服务器,服务器返回约定的 code 值时,即是需要刷新token 的时候

刷新令牌流程

这里我们可以使用发布订阅模式去处理刷新

  1. 在仓库管理中(vuex, pinia)设定一个布尔值isRefresh, 一个数组requrestList,当返回约定code时,判断isRefresh是否为true,true 的话则把请求丢进一个请求队列requestList中(即订阅), false则把请求丢进队列同时去请求刷新token的接口
  2. 拿到刷新Token接口之后有两种情况, 如果失败,清空请求队列,随后根据业务做处理即可,一般是跳转登陆页,如果成功拿到的新的Token和refreshToken, 保存起来之后,重新将请求队列中的请求依次运行释放(即发布)

Token无感知刷新示例

axios中配置请求拦截

var isRefresh = false
var requestList = []

function refreshToken() {
    // 写上你的刷新请求,以及请求成功后保存 Token 以及 循环等待请求队列
}

const instance = axios.create({
  baseURL: import.meta.env.VITE_BASE_URL,
  timeout: 30000,
  withCredentials: true // send cookies when cross-domain requests
})


// axios 响应拦截
instance.interceptors.response.use(
  (response) => {
    if (response.data.code === 401) {
        if(isRefresh) {
            isRefresh = false
            requestList.push(response.config)
            refreshToken()
        } else {
            requestList.push(response.config)
        }
        
    }
    return response.data
  },
  (error) => {
    const { errorStore } = useStore()
    LoadingUtils.hide()
    const createTime: string = ToolUtils.getNowDateTimeCn()
    const info = JSON.stringify(error)
    errorStore.addError({ id: 0, url: window.location.href, title: error, info, createTime })
    return Promise.reject(error)
  }
)

export default instance