问题 emberjs处理401未经授权


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

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

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


3723
2017-11-12 18:05


起源



答案:


AFAIK这个目前的ember-data实现并没有解决这个问题,并且ember-data README声明“处理错误状态”是在 路线图

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


2
2017-11-13 12:09



遵循这个想法,来自$ .ajax的statusCode可能是执行此操作的最佳选择。 - MilkyWayJoe
我同意将回调添加到其余适配器是这样做的方法。如果我在ember团队之前实现它,我会发布我的工作。我真的希望有人已经做过了。 - Aaron Renoir


答案:


AFAIK这个目前的ember-data实现并没有解决这个问题,并且ember-data README声明“处理错误状态”是在 路线图

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


2
2017-11-13 12:09



遵循这个想法,来自$ .ajax的statusCode可能是执行此操作的最佳选择。 - MilkyWayJoe
我同意将回调添加到其余适配器是这样做的方法。如果我在ember团队之前实现它,我会发布我的工作。我真的希望有人已经做过了。 - Aaron Renoir


截至当前版本的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


5
2017-09-28 03:47





对于那些愿意接受解决方案的人  丢失更改并声明您可以注册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语句添加适当的条件,以确保只有在您完全确定它们时才会触发事件。


2
2018-02-14 21:14



我认为该解决方案的原理可以使用,直到Ember Data实现正确的错误处理。 - jipiboily
如果它在初始化程序中完成,然后可以调用应用程序方法来执行transitionTo,这可能是一个好的解决方案。 - Ryan_IRL


它不是由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。


2
2018-04-12 18:20