2016-03-09 12 views
18

Tôi đang triển khai xác thực mã thông báo trong ứng dụng web của mình. My access token hết hạn sau mỗi N phút và hơn refresh token được sử dụng để đăng nhập và nhận access token mới.Máy đánh chặn trục và thông tin đăng nhập không đồng bộ

Tôi sử dụng Axios cho tất cả các cuộc gọi API của mình. Tôi có một thiết bị chặn được thiết lập để chặn các câu trả lời 401.

axios.interceptors.response.use(undefined, function (err) { 
    if (err.status === 401 && err.config && !err.config.__isRetryRequest) { 
    serviceRefreshLogin(
     getRefreshToken(), 
     success => { setTokens(success.access_token, success.refresh_token) }, 
     error => { console.log('Refresh login error: ', error) } 
    ) 
    err.config.__isRetryRequest = true 
    err.config.headers.Authorization = 'Bearer ' + getAccessToken() 
    return axios(err.config); 
    } 
    throw err 
}) 

Về cơ bản, khi tôi chặn phản hồi 401, tôi muốn đăng nhập và thử lại yêu cầu bị từ chối ban đầu với mã thông báo mới. My serviceRefreshLogin các cuộc gọi hàm setAccessToken() trong khối then của nó. Nhưng vấn đề là khối then xảy ra sau getAccessToken() trong trình chặn, vì vậy việc thử lại xảy ra với thông tin xác thực đã hết hạn cũ.

getAccessToken()getRefreshToken() chỉ cần trả lại mã thông báo hiện có được lưu trữ trong trình duyệt (chúng quản lý localStorage, cookie, v.v.).

Tôi làm cách nào để đảm bảo báo cáo không thực thi cho đến khi lời hứa trở lại?

(Dưới đây là một vấn đề tương ứng trên github: https://github.com/mzabriskie/axios/issues/266)

Trả lời

14

Chỉ cần sử dụng một lời hứa: D

axios.interceptors.response.use(undefined, function (err) { 
    return new Promise(function (resolve, reject) { 
     if (err.status === 401 && err.config && !err.config.__isRetryRequest) { 
      serviceRefreshLogin(
       getRefreshToken(), 
       success => { 
         setTokens(success.access_token, success.refresh_token) 
         err.config.__isRetryRequest = true 
         err.config.headers.Authorization = 'Bearer ' + getAccessToken(); 
         axios(err.config).then(resolve, reject); 
       }, 
       error => { 
        console.log('Refresh login error: ', error); 
        reject(error); 
       } 
      ); 
     } 
     throw err; 
    }); 
}); 

Nếu môi trường của bạn không suport lời hứa sử dụng polyfill, ví dụ https://github.com/stefanpenner/es6-promise

Nhưng , nó có thể tốt hơn để viết lại getRefreshToken để trả lời hứa và sau đó làm cho mã đơn giản hơn

axios.interceptors.response.use(undefined, function (err) { 

     if (err.status === 401 && err.config && !err.config.__isRetryRequest) { 
      return getRefreshToken() 
      .then(function (success) { 
       setTokens(success.access_token, success.refresh_token) ;     
       err.config.__isRetryRequest = true; 
       err.config.headers.Authorization = 'Bearer ' + getAccessToken(); 
       return axios(err.config); 
      }) 
      .catch(function (error) { 
       console.log('Refresh login error: ', error); 
       throw error; 
      }); 
     } 
     throw err; 
}); 

Demo https://plnkr.co/edit/0ZLpc8jgKI18w4c0f905?p=preview

+0

Thật không may là nó không hoạt động như thiết bị chặn. Khi tôi thử điều này, yêu cầu được thử lại chỉ SAU lời hứa ban đầu bị từ chối. –

+0

Tôi đã thực hiện plunkr https://plnkr.co/edit/0ZLpc8jgKI18w4c0f905?p=preview – ForceUser

+0

Xin lỗi, đã thêm làm rõ - Tôi không thấy nhiều ý nghĩa trong việc đưa getRefreshToken() thành lời hứa. Đó là một chức năng quản lý nội dung trên trình duyệt - luôn có một thứ có sẵn ở đó. Mã thông báo làm mới không bao giờ hết hạn BTW. –

Các vấn đề liên quan