11

我正在构建一个 ember.js 应用程序并挂断了身份验证。json rest 后端是 rails。每个请求都使用会话 cookie ( warden ) 进行身份验证。

当用户第一次导航到应用程序根时,rails 会重定向到登录页面。一旦会话被授权,ember.js 应用程序就会被加载。加载后,ember.js 应用程序使用 ember-data RESTadapter 和会话向后端发出请求以进行授权。

问题是会话将在预定时间后过期。很多时候,当这种情况发生时,ember.js 应用程序仍处于加载状态。因此,对后端的所有请求都会返回 401 {notautorized} 响应。

为了解决这个问题,我认为 ember.js 应用程序需要在每次从服务器返回 401 {not autorized} 响应时使用登录模式通知用户。

有谁知道如何收听 401 {notautorized} 响应并允许用户重新登录而不会丢失任何更改或状态。

我见过其他方法,例如令牌授权,但我担心安全隐患。

有人对这个问题有有效的解决方案吗?

4

4 回答 4

5

从 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.

于 2013-09-28T03:47:08.703 回答
2

AFAIK ember-data 的当前实现没有解决这个问题,并且 ember-data README 声明“处理错误状态”在Roadmap上。

目前,您可以实现自己的错误处理适配器。看一下DS.RestAdapter 的实现 。通过使用它作为启动器,在那里添加错误处理应该不会太难(例如,只需将错误函数添加到传递给 jQuery.ajax 调用的数据散列)。

于 2012-11-13T12:09:34.153 回答
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 请求完成并出现错误时,都会触发此代码。

当然,您永远不会真正使用这样的解决方案,因为它会造成非常糟糕的用户体验。用户被从他们正在做的事情中拉出来,他们失去了所有的状态。你真正要做的是渲染一个登录视图,可能在一个模态框内。

此解决方案的另一个优点是即使您偶尔在 ember-data 之外向您的服务器发出请求,它也能正常工作。危险在于,如果 jQuery 被用于从其他来源加载数据,或者您已经在其他地方内置了一些 401 错误处理。您需要在上面的 if 语句中添加适当的条件,以确保仅在您绝对确定它们应该触发时触发。

于 2013-02-14T21:14:44.033 回答
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。

于 2013-04-12T18:20:27.257 回答