使用rails api,backbone.js和devise进行身份验证的请求

时间:2014-08-31 18:12:38

标签: javascript ruby-on-rails backbone.js devise rails-api

我有一个使用devise for auth的rails api设置和前端的backbone.js。我能够让用户注册并登录,但我无法向api发送后续请求。我需要在签名后为每个请求附加一个身份验证令牌和一个电子邮件地址,以便提出进一步的请求,但我不知道该怎么做。

我的应用程序流程就像这样

  1. 使用custom backbone.sync
  2. 将get请求发送到/ sign_in以设置csrf标头
  3. 使用凭据向/ sign_in发送帖子请求并获取身份验证令牌
  4. 随后的每个请求发送令牌和电子邮件
  5. 每次请求发送令牌和电子邮件都是我遇到的问题。如何将其附加到骨干网中的请求?

    我应该将它添加到http标头中,就像我使用csrf令牌一样吗?

    到目前为止,这是我的设置。

    带过滤器的Api控制器

    class ApiController < ApplicationController
      respond_to :json
      before_filter :authenticate_user_from_token!
      # This is Devise's authentication
      before_filter :authenticate_api_v1_user!
    
      private
    
      def authenticate_user_from_token!
        user_email = params[:email].presence
        user = user_email && User.find_by_email(user_email)
    
        if user && Devise.secure_compare(user.authentication_token, params[:token])
          sign_in user, store: false
        end
      end
    end
    

    会话控制器

    module Api
      module V1
        class SessionsController < Devise::SessionsController
    
      skip_before_filter :authenticate_user!, only: :create
      after_action :set_csrf_header, only: [:new, :create, :destroy]
    
      def new
        render nothing: true
      end
    
      def create
        user = User.find_for_database_authentication(:email => params[:email])
    
        if user && user.valid_password?(params[:password])
          user.ensure_authentication_token  # make sure the user has a token generated
          render :json => { :user => user }, :status => :created
        else
          return invalid_login_attempt
        end
      end
    
      def destroy
        # expire auth token
        user = User.where(:authentication_token => params[:authentication_token]).first
        user.reset_authentication_token!
        render :json => { :message => ["Session deleted."] },  :success => true, :status => :ok
      end
    
      private
    
      def invalid_login_attempt
        warden.custom_failure!
        render :json => { :errors => ["Invalid email or password."] },  :success => false, :status => :unauthorized
      end
    
      def set_csrf_header
        response.headers['X-CSRF-Token'] = form_authenticity_token
      end
    
      def form_authenticity_token
        session[:_csrf_token] ||= SecureRandom.base64(32)
      end
    
    end
    end
    end
    

    覆盖backbone.sync以设置csrf标头

    require([
    'backbone',
    'router',
    'app',
    'jquery.mobile',
    'google',
    'models/session_model'
    ], function(Backbone, Router, AppView, JQMobile, google) {
        window.Droppin = window.Droppin || {};
    
    // overide backbone.sync
    Backbone._sync = Backbone.sync;
    
    Backbone.sync = function(method, model, options) {
      if (!options.noCSRF) {
        var beforeSend = options.beforeSend;
    
        // Set X-CSRF-Token HTTP header
        options.beforeSend = function(xhr) {
          var token = Droppin.csrfToken;  
          if (token) xhr.setRequestHeader('X-CSRF-Token', token);
    
          // this will include session information in the requests
          xhr.withCredentials = true;
    
          if (beforeSend) return beforeSend.apply(this, arguments);
        };
      }
    
      var complete = options.complete;
      options.complete = function(jqXHR, textStatus) {
    
         // If response includes CSRF token we need to remember it
         var token = jqXHR.getResponseHeader('X-CSRF-Token') 
         if (token) Droppin.csrfToken = token;
    
         model.trigger('sync:end');
         if (complete) complete(jqXHR, textStatus);
      };
    
      // Serialize data, optionally using paramRoot
      if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
        options.contentType = 'application/json';
        data = JSON.stringify(options.attrs || model.toJSON(options));
        if (model.paramRoot) {
          data = {};
          data[model.paramRoot] = model.toJSON(options);
        } else {
          data = model.toJSON();
        }
        options.data = JSON.stringify(data);
      }
    
      return Backbone._sync(method, model, options);
    };
    
    
    Backbone.history.start();
    new AppView();
    new Router();
    });
    

1 个答案:

答案 0 :(得分:0)

您可以全局覆盖所有jquery ajax请求,以在标题中包含某些内容。