使用Devise 3和Backbone进行用户身份验证的最佳方法是什么?

sko*_*ozz 12 login devise backbone.js ruby-on-rails-4

我正在使用这个堆栈:

  • 使用Rails 4和Devise 3.2的核心API RESTful
  • Backbone的另一个应用程序/立场

我已经阅读了很多文章,手册,stackoverflow主题,谷歌随机结果,博客等,但都非常不赞成.

使用实用的方法(tl; dr here)我只需要在不同的服务器站点中获得Devise 3和Backbone之间的真实会话并持有它,就像两个独立的项目一样.远程登录,你知道.

我真的很坚持,所以我非常感谢你的建议.

感谢你们.

Ser*_*erg 11

我个人在我的项目中使用Angular而不是Backbone作为前端和使用Devise的Rails 4 API.假设我的问题正确,我会尽力为你总结一下.

要在场景中正确使用会话,您需要确保:

  • 浏览器正确处理通信(即它们不会弄乱您的数据,因为请求不符合CORS策略)
  • 并且,您的请求通过Rails CSRF保护

请阅读有关CORS的这篇文章.如果您不熟悉CORS,那么文章应该为我的答案提供必要的背景知识.有关CSRF保护的一些信息在这里

以下是您的方案一步一步:

  1. Backbone.js发送GET请求,如http://yourserver/signin
  2. Rails Server发送将存储在浏览器中的会话cookie和CSRF令牌,它可以存储在Backbone应用程序中的某个位置.
  3. Backbone.js POST使用用户凭据(名称,密码)和头文件中的CSRF令牌以及cookie中的当前未授权会话发送请求.请求包含会话信息至关重要.否则,它将在Rails端被授予不同的CSRF令牌,您将收到WARNING: Can't verify CSRF token authenticity消息.
  4. 如果凭据正确,Backbone.js将获得授权会话.

以下是可以使其工作的方法:

  1. Rails后端应该正确响应来自前端的请求.这意味着它应该:

    • 回应OPTIONS请求(预检请求)
    • 发送正确的CORS标头
    • 能够与前端通信CSRF令牌
  2. 前端应:

    • 能够使用凭据发送请求
    • 获取并使用正确的CSRF令牌

教你的Rails后端响应CORS请求的最简单方法是使用 rack-cors gem.这也将提供正确的CORS标头.

config.middleware.insert_before Warden::Manager, Rack::Cors do
  allow do
    origins '*' # it's highly recommended to specify the correct origin
    resource '*', 
        :headers => :any, 
        :methods => [:get, :post, :options], # 'options' is really important 
                                            # for preflight requests
        :expose  => ['X-CSRF-Token']   #allows usage of token on the front-end
  end
end
Run Code Online (Sandbox Code Playgroud)

后端的最后一件事是提供CSRF令牌.Custom Devise控制器应该完美地处理这个任务.

class SessionsController < Devise::SessionsController

    after_action :set_csrf_header, only: [:new, :create, :destroy]

    #...

    protected

    def set_csrf_header
      response.headers['X-CSRF-Token'] = form_authenticity_token
    end
end
Run Code Online (Sandbox Code Playgroud)

请注意,当您发送第一个GET请求(new),通过POSTrequest(create)提交凭据以及通过发送DELETErequest(destroy)退出应用程序时,您需要CSRF令牌.如果您在注销时未发送CSRF令牌,则无法在不重新加载页面的情况下登录.

在config/routes.rb中的某处,不要忘记指定您现在使用自定义控制器:

/config/routes.rb
  devise_for :users, :controllers => {:sessions => "sessions"}
Run Code Online (Sandbox Code Playgroud)

现在,到了前端.请看一下这个覆盖标准Backbone.sync并处理与Rails服务器通信的脚本.需要进行几次修正几乎是好的:

  beforeSend: function( xhr ) {
    if (!options.noCSRF) {
      // we dont have csrf-token in the document anymore  
      //var token = $('meta[name="csrf-token"]').attr('content');

      // New Line #1
      // we will get CSRF token from your application.
      // See below for how it gets there.
      var token = YourAppName.csrfToken;

      if (token) xhr.setRequestHeader('X-CSRF-Token', token);  

      // New Line #2
      // this will include session information in the requests
      xhr.withCredentials = true;
    }

  //..some code omitted
  //................

  // Trigger the sync end event
  var complete = options.complete;
  params.complete = function(jqXHR, textStatus) {
     // New Lines #3,4
     // If response includes CSRF token we need to remember it
     var token = jqXHR.getResponseHeader('X-CSRF-Token') 
     if (token) YourAppName.csrfToken = token;

     model.trigger('sync:end');
     if (complete) complete(jqXHR, textStatus);
  };
 }
Run Code Online (Sandbox Code Playgroud)

我不确定这是否可以作为你问题的完整答案,但至少它是从一开始的.它可能不是最好的方式,但它是方式.如果您有任何疑问,请告诉我.