2014-01-16 59 views
3

Heyo,設計和AJAX:無法驗證CSRF令牌真實性跡象後

我用Rails 4和設計,並且已經覆蓋了設計的控制器,讓AJAX標誌插件和登記。這是一個單頁的應用程序。當用戶註冊時,他們可以執行所有必要的AJAX POST。但是,當他們簽署IN時,他們不能 - 我在服務器端收到「無法驗證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 

Annnd的AJAX後的問題:

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

回答

1

好吧,我想通了。這有點哈克,但它有訣竅。

當我加載一些HTML包含一個新的<%= csrf_meta_tags%>元素,並迫使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') 
    }); 
}); 

很奇怪的是,csrf_meta_tags令牌值在VIA ajax登錄時發生變化,但在註冊用戶VIA ajax時不會發生變化。奇怪,確實......如果有人有任何洞見,爲什麼這是,這將不勝感激!

+1

如果你正在使用設計。檢查此提交https://github.com/plataformatec/devise/commit/747751a2他們在登錄後清除了csrf_token – raven

-1

以防萬一再次遇到這種情況,上面的答案是正確的。

這裏is the link從設計解釋這一點。我們在控制器中使用form_authenticity_token.to_s通過ajax發回。

0

我想通過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令牌。

+1

這是一個很好的方法,但它也暴露了一個安全漏洞。如果您可以使用簡單的GET調用來獲取更新的CSRF,那麼CSRF首先要考慮的是什麼? –

相關問題