Обработка страницы аутентификации, возвращенной запросом ax ios в vue - PullRequest
2 голосов
/ 20 февраля 2020

У меня есть приложение vue, которое находится за брандмауэром, который контролирует аутентификацию. Когда вы впервые получаете доступ к приложению, вам нужно пройти аутентификацию, после чего вы можете получить доступ к приложению, и все хорошо, пока не истечет срок аутентификации. С точки зрения моего приложения я знаю только то, что пользователю необходимо повторно пройти аутентификацию, когда я использую ax ios для отправки запроса API, и вместо ожидаемой полезной нагрузки я получаю ошибку 403, которую я улавливаю с чем-то вроде следующее:

import axios  from 'axios'
var api_url = '...'

export default new class APICall {
    constructor() {
        this.axios = axios.create({
            headers: {
                'Accept': 'application/json',
                'Cache-Control': 'no-cache',
                'Content-Type': 'application/json',
            },
            withCredentials: true,
            baseURL: api_url
        });
    }
    // send a get request to the API with the attached data
    GET(command) {
        return this.axios.get(command)
            .then((response) => {
                if (response && response.status === 200) {
                    return response.data; // all good
                } else {
                    return response;      // should never happen
                }
            }).catch((err) => {
                if (err.message
                    && err.message=="Request failed with status code 403"
                    && err.response && err.response.data) {
                    // err.response.data now contains HTML for the authentication page
                    // and successful authentication on this page resends the
                    // original axios request, which is in err.response.config
                }
            })
    }
}

Внутри оператора catch, err.response.data является HTML для страницы аутентификации, и успешная аутентификация на этой странице автоматически повторно запускает исходный запрос, но я не могу на всю жизнь я вижу, как использовать это, чтобы вернуть полезную нагрузку, которую я хочу своему приложению.

Хотя это не идеально с точки зрения безопасности, я могу отображать содержимое err.response.data с помощью тега v-html, когда я сделать это, я не могу понять, как перехватить полезную нагрузку, которая возвращается, когда исходный запрос запускается страницей аутентификации, поэтому полезная нагрузка в конечном итоге отображается в браузере. Кто-нибудь знает как это сделать? Я попытался обернуть все в обещания, но я думаю, что проблема в том, что я не поставил обещание вокруг повторного запроса, так как не имею прямого контроля над ним.

Нужно ли взламывать форму в err.response.data, чтобы контролировать способ возврата данных? У меня такое ощущение, что я должен использовать перехватчик, но не совсем уверен, как они работают ...

РЕДАКТИРОВАТЬ

Я понял, что самый чистый подход - это открыть форма в error.response.data в новом окне, чтобы пользователь мог повторно пройти аутентификацию, используя что-то вроде:

var login_window = window.open('about:blank', '_blank');
login_window.document.write(error.response.data)

После успешной повторной аутентификации login_window теперь содержит json для оригинальный топор ios get запрос. Так что теперь моя проблема заключается в том, как определить, когда аутентификация срабатывает и login_window содержит json, который я хочу. Как отмечено в Обнаружение отправки формы на странице , извлечение json из окна форматирования также проблематично c, так как когда я смотрю на login_window.document.body.innerText "вручную", я вижу текстовую строку form

JSON
Raw Data
Headers
Save
Copy
Collapse All
Expand All

status  \"OK\"
message \"\"
user    \"andrew\"

но я был бы рад, если бы был надежный способ определить, когда пользователь отправляет форму входа на странице login_window, после чего я могу повторно отправить запрос.

Ответы [ 2 ]

2 голосов
/ 28 февраля 2020

Я бы выбрал другой подход, который зависит от вашего контроля над API:

  • Опция 1 : вы можете контролировать (или переносить) API
    1. иметь возврат API 401 (неавторизованный - означает, что требуется аутентификация), а не 403 (запрещенный - означает, что нет соответствующего доступа)
    2. создать REST API аутентификации (например, POST https://apiserver/auth) который возвращает новый токен аутентификации
    3. Использовать перехватчик Ax ios:
this.axios.interceptors.response.use(function onResponse(response) {
    // Any status code that lie within the range of 2xx cause this function to trigger
    // no need to do anything here
    return response;
  }, async function onResponseError(error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    if ("response" in error && "config" in error) { // this is an axios error
      if (error.response.status !== 401) { // can't handle
        return error;
      }
      this.token = await this.axios.post("auth", credentials);
      error.config.headers.authorization = `Bearer ${this.token}`;
      return this.axios.request(config);
    }
    return error; // not an axios error, can't handler
  });

В результате пользователь не испытайте это на всех, и все будет продолжаться как обычно.

  • Опция 2 : вы не можете контролировать (или переносить) API
    1. использовать перехватчик:
this.axios.interceptors.response.use(function onResponse(response) {
    // Any status code that lie within the range of 2xx cause this function to trigger
    // no need to do anything here
    return response;
  }, async function onResponseError(error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    if ("response" in error && "config" in error) { // this is an axios error
      if (error.response.status !== 403) { // can't handle
        return error;
      }
      if (!verifyLoginHtml(error.response.data)) { // this is not a known login page
        return error;
      }
      const res = await this.axios.post(loginUrl, loginFormData);
      return res.data; // this should be the response to the original request (as mentioned above)
    }
    return error; // not an axios error, can't handler
  });

2 голосов
/ 28 февраля 2020

Одним из решений является переопределение обработчика события отправки <form>, а затем использование Ax ios для отправки формы, что дает вам доступ к данным ответа формы.

Шаги:

  1. Запрос контейнера формы для элемента <form>:

    // <div ref="container" v-html="formHtml">
    const form = this.$refs.container.querySelector('form')
    
  2. Добавление события submit обработчик, который вызывает Event.preventDefault(), чтобы остановить отправку:

    form.addEventListener('submit', e => {
      e.preventDefault()
    })
    
  3. Используйте Ax ios, чтобы отправить исходный запрос, добавив свой собственный обработчик ответа, чтобы получить результирующие данные:

    form.addEventListener('submit', e => {
      e.preventDefault()
    
      axios({
        method: form.method,
        url: form.action,
        data: new FormData(form)
      })
      .then(response => {
        const { data } = response
        // data now contains the response of your original request before authentication
      })
    })
    

демо

...