Перехватчик ресурсов Vue для обновления токена JWT

Я пытаюсь написать перехватчик vue-resource, который обновляет токен доступа JWT, когда срок его действия истек. Я предполагаю, что мне нужен обратный вызов после запроса, который проверяет наличие ошибки истечения срока действия маркера (status == 401 в моем случае), а затем вызывает конечную точку обновления и повторяет первоначальный запрос.

В приведенном ниже коде единственная проблема, с которой я сталкиваюсь, заключается в том, что вызов next() после обновления токена никогда не происходит, даже если обновление выполняется нормально, а новые токены сохраняются в файле localStorage.

Vue.http.interceptors.push(function (request, next) {

    if (!request.headers.has('Authorization') && window.localStorage.access_token) {
        request.headers.set('Authorization', `Bearer ${window.localStorage.access_token}`);
    }

    next(function (response) {
        if (response.status === 401) {
            const refreshToken = localStorage.getItem('refresh_token');

            Vue.http.post('/api/v4/auth/refresh', null, {
                headers: {'Authorization': `Bearer ${refreshToken}`}
            }).then((response) => {
                localStorage.setItem('access_token', response.data.accessToken);
                localStorage.setItem('refresh_token', response.data.refreshToken);
            }).then(() => {
                next();
            });
        }
    });
})

person LIvanov    schedule 14.02.2021    source источник


Ответы (1)


Я думаю, что цепочка обратных вызовов не совсем правильная. Второй вызов next должен происходить, когда первый вызов возвращает промис, и не должен зависеть от логики, применяемой для разрешения первого промиса, а только от успешного разрешения этого промиса.

Vue.http.interceptors.push(function (request, next) {

  if (!request.headers.has('Authorization') && window.localStorage.access_token) {
    request.headers.set('Authorization', `Bearer ${window.localStorage.access_token}`);
  }

  next(function (response) {
    if (response.status === 401) {
        const refreshToken = localStorage.getItem('refresh_token');

        return Vue.http.post('/api/v4/auth/refresh', null, {
            headers: {'Authorization': `Bearer ${refreshToken}`}
        }).then((response) => {
            localStorage.setItem('access_token', response.data.accessToken);
            localStorage.setItem('refresh_token', response.data.refreshToken);
        })
    }
    return Promise.resolve(response)
  }).then(() => {
     next(); // This is called whenever the first callback returns a promise
  });
})
person Igor Moraru    schedule 14.02.2021
comment
При применении предложенных вами изменений я получаю TypeError: next(...).then is not a function. Не знаете, что именно не так? Я предполагаю, что когда response.status нет Promise, к которому можно прикрепить then? Даже если это сработает, я все еще сомневаюсь, что простой вызов next() во второй раз не сработает. Я не уверен, будет ли объект response изменен во втором вызове next() и каким образом. - person LIvanov; 15.02.2021
comment
Виноват. Первый вызов должен разрешить обещание, если статус равен 200. Я отредактировал свой ответ. Что касается последнего пункта, почему ответ должен быть изменен при втором вызове next()? - person Igor Moraru; 15.02.2021
comment
Я не думаю, что значение из return Promise.resolve(...) и return Vue.http.post когда-либо распространяется вверх по стеку next(). Это означает, что мой перехватчик вызывает next() и передает функцию, которая будет выполняться на объекте response после выполнения HTTP-вызова. Однако кажется, что результат этой функции игнорируется. - person LIvanov; 15.02.2021