emberjs处理401未经授权

时间:2012-11-12 18:05:29

标签: ember.js ember-data rails-api

我正在构建一个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}响应并允许用户重新登录而不会丢失任何更改或状态。

我已经看过其他方法,例如令牌授权,但我担心安全问题。

任何人都有解决这个问题的工作方法吗?

4 个答案:

答案 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。