BonBonSlick
@BonBonSlick
Junior Web Developer Trainee

Где проверять валидность токена пред каждым fetch api call?

Время сессии 1-2 часа, когда токен истекает его надо сбросить на клиенте.
На данный момент когда юзер пытается сделать запрос с невалидным токеном по дате ему приходит 500.
Вариант лепить проверки в каждом методе исключаем как и вариант с проверкой текста ошибки и подобных привязок.
Стек, vue 2 + fetch

Как и где бы вы проверяли валидность текущей сессии, токена на клиента перед отправкой на бек для возможности регенерации токена?

пс, сейчас юзеру надо перезагрузить страницу и тогда сработает beforeRouteEnter аля middleware, guard где идет проверка.
Но недостаток подхода в том что юзеру надо все же сделать перезагрузку страницы что контринтуитивно.
В SPA сами понимаете перезагрузка страницы только мануально, ведь мы просто загружаем и выгружаем компонент.
Хотелось бы слушатель пере каждый запросом мы ведь все-равно отправляем токен, проверить его валидность, если он невалиден то смысла запроса нет, все-равно 500 будет, а потому очищаем стейты и делаем реаутентификацию как анонимуса. Это будет более юзер френдли.
  • Вопрос задан
  • 155 просмотров
Решения вопроса 2
yarkov
@yarkov Куратор тега JavaScript
Проект "Жизнь после смерти" - lifeafterdeath.ru
Во-первых код должен быть 401.
Во-вторых посмотрите как у axios сделаны интерцепторы и напишите маленькую обёртку над fetch и там уже проверяйте что надо.
А вообще если используется refresh token, то надо не разлогинивать юзера, а обновлять access token.
Ну или тупо в setInterval засунуть запрос обновления токена.
Вариантов куча.
Ответ написан
BonBonSlick
@BonBonSlick Автор вопроса
Junior Web Developer Trainee
Моя версия
import {forEach} from 'lodash';

let callBeforeFetch: Array<Function> = [
    function checkAuthToken() {
        console.log('tested');
    },
];
let callAlways: Array<Function>      = [
    function checkAuthToken() {
        console.log('executed in finally');
    },
];

let executeFunctions = (functions: Array<Function>) => {
    forEach(functions, (func: Function): void => {
        func();
    });
};

// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
// https://developer.mozilla.org/en-US/docs/Web/API/Response/ok
export default (
    function (window: Window, fetch: Function): void {
        window.fetch = function (): Promise<Response> {
            executeFunctions(callBeforeFetch);

            const response: any = fetch.apply(this, arguments as any);
            // response.then(({ ok }) => console.log('loaded', ok));
            // response.catch(({ ok }) => console.log('loaded', ok));
            response.finally(() : void => {
                executeFunctions(callAlways);
            });

            return response;
        };

    }(window, window.fetch)
);

@Template
@Component<Main>(
    {
        router,
        store,
    },
)
class Main extends Vue {
...
    mounted(): void {
        this.logWarning();
    }

    created(): void {
        window.addEventListener('resize', this.disablePage);
        subscribeToFetchApiCalls;
    }


Оригинальный ответ SO
I don't recommend to modify native objects and functions (even the way you did with XMLHttpRequest.prototype.open). But you can replace fetch function itselt. In the end it is just a function.

(function(ns, fetch) {
  if (typeof fetch !== 'function') return;

  ns.fetch = function() {
    var out = fetch.apply(this, arguments);
    
    // side-effect
    out.then(({ ok }) => console.log('loaded', ok));

    return out;
  }

}(window, window.fetch))

fetch('https://jsonplaceholder.typicode.com/users')
fetch('https://jsonplaceholder.typicode.com/userz')


Конечно по хорошему интерсепторы но пока нужды нет. Данныая проверка будут запущена всегда при каждом запросе

https://github.com/axios/axios/blob/76f09afc03fbcf...
https://github.com/axios/axios/blob/83ae3830e4070a...
spoiler
const axios = require('axios');
const axiosApiInstance = axios.create();

// Request interceptor for API calls
axiosApiInstance.interceptors.request.use(
  async config => {
    const value = await redisClient.get(rediskey)
    const keys = JSON.parse(value)
    config.headers = { 
      'Authorization': `Bearer ${keys.access_token}`,
      'Accept': 'application/json',
      'Content-Type': 'application/x-www-form-urlencoded'
    }
    return config;
  },
  error => {
    Promise.reject(error)
});

// Response interceptor for API calls
axiosApiInstance.interceptors.response.use((response) => {
  return response
}, async function (error) {
  const originalRequest = error.config;
  if (error.response.status === 403 && !originalRequest._retry) {
    originalRequest._retry = true;
    const access_token = await refreshAccessToken();            
    axios.defaults.headers.common['Authorization'] = 'Bearer ' + access_token;
    return axiosApiInstance(originalRequest);
  }
  return Promise.reject(error);
});
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы