我正在构建一个ember.js应用程序并挂起了身份验证。 json休息后端是rails。每个请求都使用会话cookie(warden)进行身份验证。
当用户首次导航到应用程序时,root rails会重定向到登录页面。会话授权后,将加载ember.js应用程序。加载后,ember.js应用程序使用ember-data RESTadapter和会话进行授权,向后端发出请求。
问题是会话将在预定的时间后过期。很多时候,当发生这种情况时,仍然会加载ember.js应用程序。因此,对后端的所有请求都会返回401 {not autorized}响应。
要解决此问题,我认为每次从服务器返回401 {not autorized}响应时,ember.js应用程序都需要使用登录模式通知用户。
有没有人知道如何监听401 {not autorized}响应并允许用户重新登录而不会丢失任何更改或状态。
我已经看过其他方法,例如令牌授权,但我担心安全问题。
任何人都有解决这个问题的工作方法吗?
答案 0 :(得分:5)
截至当前版本的Ember Data(1.0 beta),您可以覆盖ajaxError
的{{1}}方法:
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
的{{1}}。
答案 1 :(得分:2)
AFAIK当前的ember-data实现并没有解决这个问题,并且ember-data README声明“处理错误状态”在Roadmap上。
目前,您可以实现自己的错误处理适配器。看看implementation of the DS.RestAdapter。通过使用它作为启动器,在那里添加错误处理应该不会太困难(例如,只是向传递给jQuery.ajax调用的数据哈希添加一个错误函数)。
答案 2 :(得分:2)
对于那些愿意接受 失去更改的解决方案并声明您可以注册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语句中添加适当的条件,以确保只有当你完全确定它们应该被触发时才触发。
答案 3 :(得分:2)
它不是由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。