无感刷新token

最近在做项目项目中需要无感刷新token 最近遇到了这个问题

思路

  1. 登录时获取token和用于重新获取新token的刷新refresh_token
  2. token过期接口返回错误状态码,并将此接口保存起来,让返回结果处于pending中(token过期的接口在响应拦截中不返回结果)
  3. 调接口刷新token 并记录在刷新token 此时调用的接口也保存起来,让返回结果处于pending中
  4. 重新请求token过期的接口

上代码

axios 封装文件

// axios/axios.ts
import { responseInterceptors401 } from '@/axios/index';
 responseInterceptors401 &&
 响应拦截器
this.axiosInstance.interceptors.response.use((res: any) => {
//axios方法,res接口返回结果 this.options请求配置
    return responseInterceptors401(axiosInstance, res, this.options);
}, undefined);
//settings.index.ts
// 放行接口配置文件
export const REFRESH_TOKEN_API = '/uaa-service/oauth/token';
export const LoginOUt_API = '/uaa-service/oauth/loginOut';
//axios/index.ts
import type { AxiosInstance } from 'axios';
import { LoginOUt_API, REFRESH_TOKEN_API } from '@/settings';
import { useUserStoreWithOut, getToken } from '@/store/modules/user';

//只处理接口返回code===401(token过期)拦截器
/**
 * @param axios方法
 * @param res接口返回结果
 * @param options请求配置
 */
export const responseInterceptors401 = async (axiosInstance: AxiosInstance, res: any, options) => {
  const { config, data } = res;
  const apiUrl = options.requestOptions?.apiUrl || '';

  if (data.code !== 401) return res;
  // 放行 刷新token和登出接口,刷新token接口也可能返回401,登出接口也可能401(我们的后端的确返回了所以限制一下)
  if ([apiUrl + LoginOUt_API, apiUrl + REFRESH_TOKEN_API].includes(config.url)) return res;
  const userStore = useUserStoreWithOut();
  //将请求接口保存起来 接口返回401 且不是登录和刷新token接口都存起来
  const token = getToken();
  const promise = new Promise((resolve) => {
    // 更换token
    config.headers.Authorization = options.authenticationScheme
      ? `${options.authenticationScheme} ${token}`
      : token;
    userStore.setRequests(() => resolve(axiosInstance(config)));
  });
  // 判断是否正在调用刷新token接口,没有就调用
  if (!userStore.isRefreshing) {
    await userStore.getNewToken();
    // 调用成功调用报讯接口
    userStore.requests.forEach((cb) => {
      cb();
    });
    // 接口掉完 清空保存接口数组
    userStore.requests = [];
  }
  return promise;
};

//store/modules/user.ts
interface UserState {
  token?: string;
  refreshToken?: string;
  isRefreshing: boolean; // 是否正在刷新token
  requests: Array<any>; //刷新token缓存请求信息
}

export const useUserStore = defineStore({
  id: 'user',
  state: (): UserState => ({
    token: undefined,
    refreshToken: undefined,
    isRefreshing: false,
    requests: [],
  }),
  actions: {
    /**
     * 设置token
     * @param info
     */
    setToken(info: string | undefined) {
      this.token = info ? info : ''; // for null or undefined value
    },
    /**
     * 设置刷新token
     * @param info
     */
    setRefreshToken(info: string | undefined) {
      this.refreshToken = info ? info : ''; // for null or undefined value
    },
    /**
     * 缓存请求 axiosInstance, error
     * @param requests
     */
    setRequests(requests: any) {
      this.requests.push(requests);
    },
    /**
     * 设置是否请求种状态
     * @param flag
     */
    setIsRefreshing(flag: boolean) {
      this.isRefreshing = flag;
    },
    /**
     * 刷新token
     */
    async getNewToken() {
      if (!this.isRefreshing) {
        this.setIsRefreshing(true);
        //刷新token参数
        const params: any = {
          refresh_token: this.refreshToken,
        };
        //刷新token接口 接口封装代码就不放了,每个项目封装各不相同
        const data = await API.refreshToken(params);
        if (data) {
          const { accessToken, refreshToken } = data;
          //设置新token和refreshToken
          this.setToken(accessToken);
          this.setRefreshToken(refreshToken);
          // 更改是否正在调用刷新接口状态
          this.setIsRefreshing(false);
        }
      }
    },
  },
});

export function useUserStoreWithOut() {
  return useUserStore(store);
}

上一篇:Unity3d使用Jenkins自动化打包(Windows)(一)-一、安装JDK


下一篇:ChatGPT助力学术论文写作:方法与实践