2011-04-12 64 views
3

使用Rails 3.0.6,0.2.0 Omniauth並制定1.2.1,我遇到以下情況:的Rails 3和設計:驗證用戶在執行POST操作

我要爲用戶提供了選項通過Facebook進行身份驗證。我有一個使用Devise設置的用戶系統,我可以使用Facebook成功進行身份驗證。我花了幾個小時試圖代碼我想爲一個具體情況的行爲:

  • 用戶沒有
  • 用戶登錄了一個網站帳戶
  • 用戶通過Facebook

認證我在此提供用戶2個選項

  • 創建一個帳戶(可以是一個沒有提供信息的虛擬帳戶)
  • 鏈接這個Facebook驗證與我在與後面的選項麻煩現有帳戶

。用戶已經通過身份驗證,但我仍然需要他用他的網站帳戶登錄。我在我的AuthenticationsController中執行了一項操作,該操作會將此身份驗證與登錄的用戶相關聯。儘管如此,Devise似乎沒有提供讓我登錄用戶的方法。這是我第一次做這個

class AuthenticationsController < ApplicationController 
    before_filter :authenticate_user!, :only => :auth_link_existing_user 

    ... 

    def auth_link_existing_user 
    ... 
    end 

但是嘗試,使用這種方法,如果用戶登錄時,他們只是簡單地重定向到我的網站的根頁。我知道我可以更改Devise的登錄重定向,但這將適用於所有登錄。我只想要這種情況有一個單獨的重定向。

通過this郵件列表的問題看完後,我試圖用我自己的自定義行爲擴展SessionsController

def create 
    resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new") 
    set_flash_message(:notice, :signed_in) if is_navigational_format? 
    sign_in(resource_name, resource) 
    if params[:redirect]       #new 
    redirect_to params[:redirect].to_sym   #new 
    else 
    respond_with resource, :location => redirect_location(resource_name, resource) 
    end 

end 

這也不起作用。我已經將我的auth_link_existing_user路線定義爲使用POST動詞(這看起來很準確),重定向只能是GET。

因此,現在我確實有一個解決方案:將Devise的authenticate_user!幫手中的代碼複製並粘貼到一個新的函數中,該函數可以在控制器操作中調用而不用重定向。這對我來說似乎不太理想,因爲它是代碼的重複並增加了耦合 - 更改此行爲的Devise或Warden更新也會破壞我的代碼。

有沒有其他人試過這樣的東西,想出一個更優雅的解決方案?您是否看到一種更簡單的方式來向我的用戶提供此類或類似的行爲?

UPDATE:誰想要在最後用我的骯髒的解決方案,這是我做的:

def auth_link_existing_user 
    # FROM Devise/sessions/create 
    resource = warden.authenticate!(:scope => :user, :recall => "registrations#auth_new") 
    set_flash_message(:notice, :signed_in) if is_navigational_format? 
    sign_in(:user, resource) 

    # method defined in Ryan Bates' Railscast for Omniauth w/Devise 
    current_user.apply_omniauth(session[:omniauth]) 
    current_user.save 
end 

注意,此操作MUST被放置在您的會話控制器。否則,Warden會給你一個「無效的電子郵件/密碼」錯誤。找到源代碼的調試過程非常漫長。

使用此功能後,我使用登錄表單在用戶通過身份驗證後提交此操作。

回答

0

我喜歡你的解決方案是多麼的乾淨,儘管它更深入瞭解堆棧。

這裏是如何,我實現了由以下的Devise wiki的設計+ Omniauth Facebook的例子和修改facebook方法類似的東西來傳遞會話信息的登錄表單,像這樣的東西:

if @user.persisted? 
    flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook" 
    sign_in_and_redirect @user, :event => :authentication 

else 
    session["devise.facebook_data"] = request.env["omniauth.auth"] 
    redirect_to new_user_session_url 
end 

然後,對於您的情況,我會在登錄控制器操作session["devise.facebook_data"]中檢查,提交帶有窗體和apply_omniauth(如果存在)的uid +標記。