我正在构建一个ember.js应用程序,我挂了认证。 json休息后端是rails。每个请求都使用会话cookie进行身份验证(看守)。
当用户首次导航到应用程序根轨道重定向到登录页面时。一旦会话被授权,就会加载ember.js应用程序。加载后,ember.js应用程序使用ember-data RESTadapter和会话进行授权,向后端发出请求。
问题是会话将在预定的时间后过期。很多时候,当发生这种情况时,仍然会加载ember.js应用程序。因此,对后端的所有请求都会返回401 {not autorized}响应。
为了解决这个问题,我认为每次从服务器返回401 {not autorized}响应时,ember.js应用程序都需要通过登录模式通知用户。
有谁知道如何监听401 {not autorized}响应并允许用户重新登录而不会丢失任何更改或状态。
我见过其他方法,如令牌授权,但我担心安全问题。
有人有解决这个问题的工作方法吗?
AFAIK这个目前的ember-data实现并没有解决这个问题,并且ember-data README声明“处理错误状态”是在 路线图。
目前,您可以实现自己的错误处理适配器。看看吧 DS.RestAdapter的实现 。通过使用它作为启动器,在那里添加错误处理应该不会太困难(例如,简单地将错误函数添加到传递给jQuery.ajax调用的数据散列中)。
AFAIK这个目前的ember-data实现并没有解决这个问题,并且ember-data README声明“处理错误状态”是在 路线图。
目前,您可以实现自己的错误处理适配器。看看吧 DS.RestAdapter的实现 。通过使用它作为启动器,在那里添加错误处理应该不会太困难(例如,简单地将错误函数添加到传递给jQuery.ajax调用的数据散列中)。
截至当前版本的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
。
对于那些愿意接受解决方案的人 不 丢失更改并声明您可以注册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被用于从其他来源加载数据,或者你是否已经在其他地方内置了一些401错误处理。您需要为上面的if语句添加适当的条件,以确保只有在您完全确定它们时才会触发事件。
它不是由ember-data(也可能不是)解决的,但你可以重新打开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's 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's 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's ajax method handle the call
this._super(url, type, hash);
}
});
我们在这里做的基本上是推迟收到401的调用,并保留在登录完成后再次调用的请求。模态的ajax调用具有从原始ajax调用的哈希应用于它的原始错误,因此原始错误仍然可以工作,只要它定义:-)
这是我们在自己的数据持久性库中使用的一些修改后的实现,因此您的实现可能会有所不同,但同样的概念应该适用于ember-data。