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 и подписать каждый запрос с помощью токена. Сервер проверяет токен, и если он проверяет, он возвращает данные. Таким образом, вам не нужно проверять переменные сеанса, срок действия которых истекает через короткий период.