Webアプリにトークン認証を実装しています。 _access token
_はN分ごとに期限切れになり、_refresh token
_を使用してログインし、新しい_access token
_を取得します。
すべてのAPI呼び出しにAxiosを使用しています。 _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
})
_
基本的に、401応答をインターセプトする際に、ログインを行い、拒否された元の要求を新しいトークンで再試行します。 serviceRefreshLogin
関数は、then
ブロックでsetAccessToken()
を呼び出します。しかし問題は、インターセプターのthen
ブロックがgetAccessToken()
よりも遅く発生するため、古い期限切れの資格情報で再試行が行われることです。
getAccessToken()
およびgetRefreshToken()
は、ブラウザに保存されている既存のトークンを返します(localStorage、Cookieなどを管理します)。
約束が戻るまで文が実行されないようにするにはどうすればよいですか?
(githubの対応する問題は次のとおりです。 https://github.com/mzabriskie/axios/issues/266 )
別の約束を使用してください: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;
});
});
環境が約束をサポートしていない場合、ポリフィルを使用します。たとえば、 https://github.com/stefanpenner/es6-promise
ただし、getRefreshTokenを書き換えてpromiseを返し、コードを単純にする方が良い場合があります
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;
});
応答の代わりに要求でそれを行うことができます。アクセストークンの有効期限が切れたときにサーバーにヒットすることを避けるため、おそらくよりクリーンになります。 この記事 からのコピー:
function issueToken() {
return new Promise((resolve, reject) => {
return client({
...
}).then((response) => {
resolve(response);
}).catch((err) => {
reject(err);
});
});
}
client.interceptors.request.use((config) => {
let originalRequest = config;
if (tokenIsExpired && path_is_not_login) {
return issueToken().then((token) => {
originalRequest['Authorization'] = 'Bearer ' + token;
return Promise.resolve(originalRequest);
});
}
return config;
}, (err) => {
return Promise.reject(err);
});