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