簡體   English   中英

設計和AJAX:登錄后無法驗證CSRF令牌的真實性

[英]Devise and AJAX: Can't verify CSRF token authenticity after sign in

Heyo,

我正在使用Rails 4和Devise,並且已經覆蓋了Devise控制器以允許AJAX登錄和注冊。 這是一個單頁的應用程序。 當用戶注冊時,他們可以執行所有必要的AJAX POST。 然而,當他們登錄時,他們不能 - 我在服務器端獲得“無法驗證CSRF令牌真實性”。 這種情況發生在我刷新頁面之前 - 然后CSRF令牌更新,我可以正常POST。

知道為什么這會在注冊用戶登錄后發生,而不是在注冊或頁面刷新后發生? 這是我的控制器中的代碼:

class SessionsController < Devise::SessionsController
  def create
    resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
    sign_in_and_redirect(resource_name, resource)
  end

  def sign_in_and_redirect(resource_or_scope, resource=nil)
    scope = Devise::Mapping.find_scope!(resource_or_scope)
    resource ||= resource_or_scope
    sign_in(scope, resource) unless warden.user(scope) == resource
    @badge = resource.badge
    return render 'signin.js.erb'
  end

  def failure
    return render :json => {:success => false, :errors => ["Login failed."]}
  end

  def destroy
    redirect_path = '/labs'
    signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))    
    yield resource if block_given?

    # We actually need to hardcode this as Rails default responder doesn't
    # support returning empty response on GET request
    respond_to do |format|
      format.all { head :no_content }
      format.any(*navigational_formats) { redirect_to redirect_path }
    end
  end
end

和我的注冊控制器:

class RegistrationsController < Devise::RegistrationsController

  def create
    build_resource(sign_up_params)

    if resource.save
      if resource.active_for_authentication?
        set_flash_message :notice, :signed_up if is_navigational_format?
        sign_up(resource_name, resource)
        return render 'signup.js.erb'
      else
        set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
        expire_session_data_after_sign_in!
        return render :json => {:success => true}
      end
    else
      clean_up_passwords resource
      return render :json => {:success => false}
    end
  end

  # Signs in a user on sign up. You can overwrite this method in your own
  # RegistrationsController.
  def sign_up(resource_name, resource)
    sign_in(resource_name, resource)
  end

end

宣傳有問題的AJAX帖子:

$(document).on('click', '.project_item', function () {
    $.ajax({
      type: "POST",
      url: '/hammer/thing_toggle',
      data: 'id=' + $(this).data('id')
    });
});

好吧,我明白了。 這有點像hacky,但它確實可以解決問題。

當用戶登錄時,我加載一些包含新的<%= csrf_meta_tags%>元素的HTML,並強制AJAX請求使用該新標記:

$(document).on('click', '.project_item', function () {
    $.ajax({
      type: "POST",
      beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').last().attr('content'))},
      url: '/hammer/thing_toggle',
      data: 'id=' + $(this).data('id')
    });
});

奇怪的是,在簽署VIA ajax時csrf_meta_tags標記值會發生變化,但是當我注冊用戶VIA ajax時則不會。 確實很奇怪......如果有人對此有什么了解,那就不勝感激了!

我想當使用AJAX使用Devise登錄時,存儲在會話中的csrf_token會被清除。 我必須在登錄后編寫一個API來生成一個新的csrf_token。調用它並在html標題中更新我的csrf_token。

我的api_controller.rb:

class ApiController < ApplicationController

  def reload_csrf 
    render json: { csrf: form_authenticity_token }, status: :ok
  end

end

sign_in后我的AJAX調用:

// Get and set new csrf token after the new session
  $.ajax({
    type: "GET",
    url: "/reload_csrf.json",
    success:function(response) {
      $('meta[name="csrf-token"]').attr('content', response.csrf);
    }
  });

然后我的所有表單提交將使用新的有效csrf標記。

如果有人再遇到這個,上面的答案是正確的。

設計解釋這個的鏈接 我們在控制器中使用form_authenticity_token.to_s通過ajax將其發回。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM