vue axios tokenリフレッシュ--vueバックグラウンド管理

38099 ワード

需要
最近、プロジェクトを書き、バックエンドとtokenリフレッシュスキームについて議論しています.フロントエンドがログインした後、バックエンドはtokenとrefreshTokenの有効時間に戻り、tokenが期限切れになったときにrefreshTokenで新しいtokenを取得する必要があります.フロントエンドはtokenを無痛にリフレッシュする必要があります.つまり、tokenのリフレッシュを要求するときは、ユーザーが感知しないようにします.
ぶんせき
フロントエンドログイン後はtokenrefreshTokenに戻ります.token 30分失効refreshToken 1日失効、この時間差で無痛リフレッシュtoken
方法1:要求を開始した後、tokenが期限切れになった後にrefreshTokenインタフェースを呼び出して新しいtokenを取得し、バーの前の要求を実行します.refreshTokenが期限切れになったら、直接ログインページに戻ります.
方法2:バックエンドにtokenの期限切れのフィールドが提供され、要求が開始される前に各要求をブロックし、tokenの有効時間が期限切れであるかどうかを判断し、期限切れであれば要求を保留し、tokenをリフレッシュしてから要求を継続する.
インプリメンテーション
ここでは、バックエンドにデータを返すことを約束する方法を実装します.例えば、次のようにします.
{code: 418, message: 'token  ', data: {}}

import axios from "axios";

const instance = axios.create({
  baseURL: process.env.BASE_API, // url = base url + request url

  // timeout: 5000 // request timeout
  withCredentials: true,
 
});

//        setToken  ,        token     header,   token   localStorage 
instance.setToken = (token,refreshToken) => {
instance.defaults.headers['Authorization'] = `Auth ${token}`
//         localStorage
window.localStorage.setItem('token', token)
  
window.localStorage.setItem('refreshToken', refreshToken)
}

function refreshToken () {

  //         token       token   refreshToken                
  window.localStorage.setItem('token', window.localStorage.refreshToken)
  return instance({method:'post',url: '/api-token-refresh'})
}
  //              token        
function removeToken () {
  window.localStorage.removeItem('token')
  window.localStorage.removeItem('refreshToken')

}

//      
instance.interceptors.request.use(
  config => {
    //           vuex     token
    //     ,    http   header   token,      token        
    //       token,    token    ,                   
    
    
    const token = window.localStorage.token;

    token && (config.headers.Authorization = `Auth ${token}`);


 
    return config;
  },
  error => {
    return Promise.error(error);
  }
);


//          
let isRefreshing = false
//     ,               
let requests = []
//      
instance.interceptors.response.use(
  response => {
    const res = response.data


    if(res.code === 418){
            const config = response.config
      if (!isRefreshing) {
        isRefreshing = true
       
          
        
        return refreshToken().then(res => {
    
          const { token ,refreshToken} = res.data
         
          
          instance.setToken(token,refreshToken)
          config.headers['Authorization'] = `Auth ${token}`
          config.baseURL = ''
          console.log('token      ');
           //                                          
          //      token,             
          
          requests.forEach(cb => cb(token))
          requests = []
          return instance(config)
        },err=>{
          console.log(err)
          
        }).catch(res => {

         
          removeToken()
          router.push('/login')
          console.error('refreshtoken error =>', res)
         
          
        }).finally(() => {
          console.log('  ');
          
          isRefreshing = false
        })
      }else {
        //     token,        resolve promise
        //          
        //                       
        return new Promise((resolve) => {
          //  resolve    ,          , token       
          requests.push((token) => {
            config.baseURL = ''
            config.headers['Authorization'] = `Auth ${token}`
            resolve(instance(config))
          })
        })
        
      }
    
    }  

  
    
 

    
     if (res.code === 0) {
   //        
      return Promise.reject(res);
      // return res
    }
    return res
  },
  error => {
     console.log(error);
  
    return Promise.reject();
  }
);

export { instance };

最適化
質問:
tokenが期限切れになった場合、refreshTokenメソッドを呼び出した後、新しいtokenを取得して送信する前のリクエストを送信します.このとき、バックエンドが処理されていなければ400ステータスコードに戻ってcatchに入り、再ログインの操作を実行する必要があります.
解決方法:catchでtokenの削除とログインページへのジャンプ操作を行う必要はありません.refreshTokenが期限切れになると、バックエンドは{code: 419, message: 'refreshToken , ', data: {}}に戻ります.もちろん、tokenが合法ではないtokenが認証されていない場合もあります.
完全なコード

import axios from "axios";

const instance = axios.create({
  baseURL: process.env.BASE_API, // url = base url + request url

  // timeout: 5000 // request timeout
  withCredentials: true,
 
});

//        setToken  ,        token     header,   token   localStorage 
instance.setToken = (token,refreshToken) => {
instance.defaults.headers['Authorization'] = `Auth ${token}`
//         localStorage
window.localStorage.setItem('token', token)
  
window.localStorage.setItem('refreshToken', refreshToken)
}

function refreshToken () {

  //         token       token   refreshToken                
  window.localStorage.setItem('token', window.localStorage.refreshToken)
  return instance({method:'post',url: '/api-token-refresh'})
}
  //              token        
function removeToken () {
  window.localStorage.removeItem('token')
  window.localStorage.removeItem('refreshToken')

}

//      
instance.interceptors.request.use(
  config => {
    //           vuex     token
    //     ,    http   header   token,      token        
    //       token,    token    ,                   
    
    
    const token = window.localStorage.token;

    token && (config.headers.Authorization = `Auth ${token}`);


 
    return config;
  },
  error => {
    return Promise.error(error);
  }
);


//          
let isRefreshing = false
//     ,               
let requests = []
//      
instance.interceptors.response.use(
  response => {
    const res = response.data
    // refreshToken      token    token    
    if(res.code === 419||420||421){
         removeToken()
         router.push('/login')
        return Promise.reject(res);
    }
    
    if(res.code === 418){
            const config = response.config
      if (!isRefreshing) {
        isRefreshing = true
       
          
        
        return refreshToken().then(res => {
    
          const { token ,refreshToken} = res.data
         
          
          instance.setToken(token,refreshToken)
          config.headers['Authorization'] = `Auth ${token}`
          config.baseURL = ''
          console.log('token      ');
           //                                          
          //      token,             
          
          requests.forEach(cb => cb(token))
          requests = []
          return instance(config)
        },err=>{
          console.log(err)
          
        }).catch(res => {

         
         
          console.error('refreshtoken error =>', res)
         
          
        }).finally(() => {
          console.log('  ');
          
          isRefreshing = false
        })
      }else {
        //     token,        resolve promise
        //          
        //                       
        return new Promise((resolve) => {
          //  resolve    ,          , token       
          requests.push((token) => {
            config.baseURL = ''
            config.headers['Authorization'] = `Auth ${token}`
            resolve(instance(config))
          })
        })
        
      }
    
    }  

  
    
 

    
     if (res.code === 0) {
   //        
      return Promise.reject(res);
      // return res
    }
    return res
  },
  error => {
     console.log(error);
  
    return Promise.reject();
  }
);

export { instance };

みんなに役に立つことを望みます!!