Я использую следующее промежуточное ПО для обновления токена по истечении срока его действия:
import {AsyncStorage} from 'react-native';
import moment from 'moment';
import fetch from "../components/Fetch";
import jwt_decode from 'jwt-decode';
/**
* This middleware is meant to be the refresher of the authentication token, on each request to the API,
* it will first call refresh token endpoint
* @returns {function(*=): Function}
* @param store
*/
const tokenMiddleware = store => next => async action => {
if (typeof action === 'object' && action.type !== "FETCHING_TEMPLATES_FAILED") {
let eToken = await AsyncStorage.getItem('eToken');
if (isExpired(eToken)) {
let rToken = await AsyncStorage.getItem('rToken');
let formData = new FormData();
formData.append("refresh_token", rToken);
await fetch('/token/refresh',
{
method: 'POST',
body: formData
})
.then(response => response.json())
.then(async (data) => {
let decoded = jwt_decode(data.token);
console.log({"refreshed": data.token});
return await Promise.all([
await AsyncStorage.setItem('token', data.token).then(() => {return AsyncStorage.getItem('token')}),
await AsyncStorage.setItem('rToken', data.refresh_token).then(() => {return AsyncStorage.getItem('rToken')}),
await AsyncStorage.setItem('eToken', decoded.exp.toString()).then(() => {return AsyncStorage.getItem('eToken')}),
]).then((values) => {
return next(action);
});
}).catch((err) => {
console.log(err);
});
return next(action);
} else {
return next(action);
}
}
function isExpired(expiresIn) {
// We refresh the token 3.5 hours before it expires(12600 seconds) (lifetime on server 25200seconds)
return moment.unix(expiresIn).diff(moment(), 'seconds') < 10;
}
};
export default tokenMiddleware;
И помощник по поиску
import { AsyncStorage } from 'react-native';
import GLOBALS from '../constants/Globals';
import {toast} from "./Toast";
import I18n from "../i18n/i18n";
const jsonLdMimeType = 'application/ld+json';
export default async function (url, options = {}, noApi = false) {
if ('undefined' === typeof options.headers) options.headers = new Headers();
if (null === options.headers.get('Accept')) options.headers.set('Accept', jsonLdMimeType);
if ('undefined' !== options.body && !(options.body instanceof FormData) && null === options.headers.get('Content-Type')) {
options.headers.set('Content-Type', jsonLdMimeType);
}
let token = await AsyncStorage.getItem('token');
console.log({"url": url,"new fetch": token});
if (token) {
options.headers.set('Authorization', 'Bearer ' + token);
}
let api = '/api';
if (noApi) {
api = "";
}
const link = GLOBALS.BASE_URL + api + url;
return fetch(link, options).then(response => {
if (response.ok) return response;
return response
.json()
.then(json => {
if (json.code === 401) {
toast(I18n.t(json.message), "danger", 3000);
AsyncStorage.setItem('token', '');
}
const error = json['message'] ? json['message'] : response.statusText;
throw Error(I18n.t(error));
})
.catch(err => {
throw err;
});
})
.catch(err => {
throw err;
});
}
Моя проблема:
- когда я совершаю действие, промежуточное ПО называется.
- Если срок действия токена истекает, вызывается метод обновления токена и обновляется AsyncStorage.
- Затем должен вызываться метод
next(action)
. - Но моя конечная точка
/templates
вызывается до (а не после) конечной точки my/token/refresh
с использованием старого просроченного токена... - Тогда следствием этого является то, что мой текущий экран возвращает ошибку (неавторизовано), но если пользователь изменит экран, он снова будет работать, поскольку его токен был успешно обновлен. Но это так безобразно: p
РЕДАКТИРОВАТЬ: Ради этой проблемы, я переработал свой код, чтобы поместить это в один файл. Я также поместил немного console.log, чтобы показать, как этот код будет выполняться
Из изображения видно, что:
- Мои вызовы (/шаблоны) выполняются до моей конечной точки обновления. И мой консольный журнал обновленного токена приходит спустя много времени после этого...
Любая помощь в этом, пожалуйста?
РЕДАКТИРОВАТЬ до конца щедрости:
Исходя из этого вопроса, я пытаюсь понять, почему мой подход неверен в отношении промежуточного программного обеспечения, поскольку многие ресурсы, которые я нашел в Интернете, говорят о промежуточном программном обеспечении как о наилучшем решении для выполнения операций обновления токена.