Emberjs handle 401 не авторизован

Я создаю приложение ember.js и нахожусь на проверке подлинности. Бэкэнд для отдыха json - рельсы. Каждый запрос аутентифицируется с использованием файла cookie сеанса (warden).

Когда пользователь сначала переходит к корневому рельсу приложения, перенаправление на страницу входа в систему. После авторизации сеанса загружается приложение ember.js. После загрузки приложение ember.js отправляет запросы на бэкэнд, используя RESTadapter на основе ember-данных и сеанс для авторизации.

Проблема заключается в том, что сеанс истечет через заданное время. Много раз, когда это происходит, приложение ember.js по-прежнему загружается. Таким образом, все запросы на бэкэнд возвращают 401 {не авторизованный} ответ.

Чтобы исправить эту проблему, я думаю, что приложение ember.js должно уведомлять пользователя с модой входа каждый раз, когда с сервера возвращается ответ 401 {не авторизованный}.

Кто-нибудь знает, как прослушать 401 {не авторизованный} ответ и разрешить пользователю повторно войти в систему, не теряя никаких изменений или состояний.

Я видел другие подходы, такие как авторизация токена, но я обеспокоен последствиями безопасности.

У кого-нибудь есть рабочее решение этой проблемы?

Ответ 1

AFAIK это не устраняется текущей реализацией данных ember-данных, а README из ember-данных указывает, что "State error error" находится на Roadmap.

В настоящее время вы можете реализовать свой собственный адаптер обработки ошибок. Взгляните на реализацию DS.RestAdapter. Используя это как стартер, не должно быть слишком сложно добавить в него обработку ошибок (например, просто добавьте функцию ошибки в хэш данных, который передается вызову jQuery.ajax).

Ответ 2

В текущей версии Ember Data (1.0 beta) вы можете переопределить метод ajaxError DS.RESTAdapter:

App.ApplicationAdapter = DS.RESTAdapter.extend({
  ajaxError: function(jqXHR) {
    var error = this._super(jqXHR);
    if (jqXHR && jqXHR.status === 401) {
      #handle the 401 error
    }
    return error;
  }
});

Обратите внимание, что вы должны называть @_super, особенно если вы переопределяете один из более сложных адаптеров, например DS.ActiveModelAdapter, который обрабатывает 422 Unprocessable Entity.

Ответ 3

Для тех, кто хочет принять решение, которое потеряет изменения и состояние, вы можете зарегистрировать обработчик jQuery ajaxError для перенаправления на страницу входа.

$(document).ajaxError(function(event, jqXHR, ajaxSettings, thrownError) {
  // You should include additional conditions to the if statement so that this
  // only triggers when you're absolutely certain it should
  if (jqXHR.status === 401) {
    document.location.href = '/users/sign_in';
  }
});

Этот код запускается в любое время, когда любой запрос jQuery ajax завершается с ошибкой.

Конечно, вы никогда бы не использовали такое решение, так как оно создавало невероятно плохой пользовательский интерфейс. Пользователь отрывается от того, что они делают, и они теряют все состояние. То, что вы на самом деле делаете, - это сделать LoginView, возможно, внутри модального.

Другим достоинством этого решения является то, что он работает, даже если вы иногда делаете запросы на свой сервер вне данных ember-data. Опасность заключается в том, что jQuery используется для загрузки данных из других источников или если у вас уже есть некоторая ошибка обработки ошибок, встроенная в другое место. Вы хотите добавить соответствующие условия в оператор if выше, чтобы убедиться, что все происходит только тогда, когда вы абсолютно уверены, что они должны.

Ответ 4

Он не адресован ember-данными (и, вероятно, не будет), но вы можете снова открыть класс DS и расширить метод ajax.

Он выглядит следующим образом:

ajax: function(url, type, hash) {
  hash.url = url;
  hash.type = type;
  hash.dataType = 'json';
  hash.contentType = 'application/json; charset=utf-8';
  hash.context = this;

  if (hash.data && type !== 'GET') {
    hash.data = JSON.stringify(hash.data);
  } 

  jQuery.ajax(hash);
},

Вы можете переписать его с чем-то вроде этого (отказ от ответственности: непроверенный, вероятно, не будет работать):

DS.reopen({
    ajax: function(url, type, hash) {
        var originalError = hash.error;
        hash.error = function(xhr) {
            if (xhr.status == 401) {
                var payload = JSON.parse(xhr.responseText);
                //Check for your API errorCode, if applicable, or just remove this conditional entirely
                if (payload.errorCode === 'USER_LOGIN_REQUIRED') {
                    //Show your login modal here
                    App.YourModal.create({
                        //Your modal callback will process the original call
                        callback: function() {
                            hash.error = originalError;
                            DS.ajax(url, type, hash);
                        }
                    }).show();
                    return;
                }
            }
            originalError.call(hash.context, xhr);
        };
        //Let ember-data ajax method handle the call
        this._super(url, type, hash);
    }
});

То, что мы делаем здесь, по существу, откладывает вызов, который получил 401, и сохраняет запрос для повторного вызова, когда логин завершен. Модальный вызов ajax с исходной ошибкой, применяемой к нему из исходного хэша вызова ajax, поэтому исходная ошибка будет работать до тех пор, пока она определена: -)

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

Ответ 5

Другой способ обойти эту проблему - использовать OAuth и подписать каждый запрос с помощью токена. Сервер проверяет токен, и если он проверяет, он возвращает данные. Таким образом, вам не нужно проверять переменные сеанса, срок действия которых истекает через короткий период.