Я хотел бы знать, можно ли это сделать, потому что я не уверен, что я ошибаюсь или если это невозможно. В принципе, я хочу создать функцию переноса для встроенной функции javascript fetch
. Эта функция обертки реализует процесс проверки токена, запрашивая новый accessToken
, если тот, который указан, истек и запрашивает снова желаемый ресурс. Это то, что я не достигли до сих пор:Wrap javascript fetch для добавления пользовательских функций
customFetch.js
// 'url' and 'options' parameters are used strictely as you would use them in fetch. 'authOptions' are used to configure the call to refresh the access token
window.customFetch = (url, options, authOptions) => {
const OPTIONS = {
url: '',
unauthorizedRedirect: '',
storage: window.sessionStorage,
tokenName: 'accessToken'
}
// Merge options passed by user with the default auth options
let opts = Object.assign({}, OPTIONS, authOptions);
// Try to update 'authorizarion's header in order to send always the proper one to the server
options.headers = options.headers || {};
options.headers['Authorization'] = `Bearer ${opts.storage.getItem(opts.tokenName)}`;
// Actual server request that user wants to do.
const request = window.fetch(url, options)
.then((d) => {
if (d.status === 401) {
// Unauthorized
console.log('not authorized');
return refreshAccesToken();
}
else {
return d.json();
}
});
// Auxiliar server call to get refresh the access token if it is expired. Here also check if the
// cookie has expired and if it has expired, then we should redirect to other page to login again in
// the application.
const refreshAccesToken =() => {
window.fetch(opts.url, {
method: 'get',
credentials: 'include'
}).then((d) => {
// For this example, we can omit this, we can suppose we always receive the access token
if (d.status === 401) {
// Unauthorized and the cookie used to validate and refresh the access token has expired. So we want to login in to the app again
window.location.href = opts.unauthorizedRedirect;
}
return d.json();
}).then((json) => {
const jwt = json.token;
if (jwt) {
// Store in the browser's storage (sessionStorage by default) the refreshed token, in order to use it on every request
opts.storage.setItem(opts.tokenName, jwt);
console.log('new acces token: ' + jwt);
// Re-send the original request when we have received the refreshed access token.
return window.customFetch(url, options, authOptions);
}
else {
console.log('no token has been sent');
return null;
}
});
}
return request;
}
consumer.js
const getResourcePrivate =() => {
const url = MAIN_URL + '/resource';
customFetch(url, {
method: 'get'
},{
url: AUTH_SERVER_TOKEN,
unauthorizedRedirect: AUTH_URI,
tokenName: TOKEN_NAME
}).then((json) => {
const resource = json ? json.resource : null;
if (resource) {
console.log(resource);
}
else {
console.log('No resource has been provided.');
}
});
}
Я попытаюсь объяснить немного лучше приведенный выше код: Я хочу сделать прозрачным для пользователей проверку маркера, чтобы позволить им просто беспокоиться о запросе требуемого им ресурса. Этот подход работает нормально, когда accessToken
по-прежнему действует, поскольку инструкция return request
дает потребителю обещание запроса fetch
.
Конечно, когда accessToken
истек, и мы запрашиваем новый сервер auth
, это не работает. Маркер обновляется и запрашивается частный ресурс, но consumer.js
его не видит.
Для этого последнего сценария можно изменить поток программы, чтобы обновить accessToken
и выполнить вызов сервера, чтобы снова получить частный ресурс? Потребитель не должен понимать об этом процессе; в обоих случаях (accessToken
действителен и accessToken
истек и был обновлен) consumer.js
должен получить частный запрашиваемый ресурс в своей функции then
.
О, я думаю, я уже слишком поздно: DI хотел предложить удалить один набор скобок здесь. Const refreshAccesToken =() => window.fetch (...); 'Этот способ' refreshAccesToken' должен возвращать обещание, вместо 'undefined', и все должно работать нормально –
@ Dennis вы правы!Я сделал ошибку в этой функции, и я забыл вернуть обещание. Я пробовал, и все работает отлично, поэтому я отредактирую свой ответ, чтобы добавить ваш подход, который был еще ближе к моему внутреннему решению. – christiansr85