2011-08-29 121 views
7

我們有一個使用devise & omniauth允許通過Facebook身份驗證登錄的rails應用程序設置。我們還有一個移動應用程序,它目前使用http身份驗證登錄到Rails應用程序,方法是通過傳遞用戶名&密碼或傳入http身份驗證令牌。迄今爲止,這一切都很有效。如何使用可選omniauth令牌作爲身份驗證令牌使用http身份驗證

該移動應用程序還具有使用Facebook本身進行身份驗證以及在其本身和Facebook之間直接接收用戶Facebook令牌的能力。

我想填補這個空白,以便如果用戶通過Facebook從移動應用程序登錄並擁有他們的Facebook令牌,則允許將這個Facebook令牌用作Rails應用程序的身份驗證,就好像他們已收到它從Facebook通過瀏覽器。

最終的結果將是,移動應用可以登錄用戶經由:

1)用戶名/密碼 或 2)HTTP認證令牌 或 3)omniauth(Facebook)的令牌

另外,在3)的情況下,如果用戶還沒有存在於Rails應用程序中,則需要創建用戶 - 現在已經使用瀏覽器側認證,因此可能沒有什麼可做的了。

我該如何在設計構造中最好地完成這件事?

回答

10

剛剛做到了這一點,但從未見過端到端的解決方案。

此地址點3. 1 & 2很容易實現設計和記錄在別處。

不難將FB認證添加到您的網絡應用程序中,說明在github上爲omniauth和omniauth-facebook。

我相信如果你想這樣做,以下是獨立的,沒有做omniauth-facebook集成。這與其他方法類似。我的想法是試圖儘可能使用設計模型。

您將需要fb_graph寶石。

在移動客戶端上,您可以使用FB進行相應的身份驗證,並將返回的訪問令牌放入您的http請求的頭部。我使用頭fb_access_token。 就像基本身份驗證一樣,您需要通過SSL發送該消息以避免嗅探令牌。使用頭允許我在不更改請求的情況下交換基本身份驗證和FB身份驗證,但是如果您願意,可以使用參數。

該解決方案實現了基於設計Authenticatable監管策略的監獄戰略。這裏的區別在於這個策略使用了一個名爲fb_access_token的HTTP頭,其中包含使用移動應用程序檢索到的Facebook訪問令牌字符串。

一旦你知道這一點,代碼是非常簡單的。

在文件中,在config/initializers目錄中添加以下內容。我碰巧打電話給我的fb_api_strategy。RB:

# authentication strategy to support API authentication over the webservice 
# via facebook 

require 'devise/strategies/database_authenticatable' 
require 'fb_graph' 
require 'warden' 

module Devise 
    module Strategies 
    class FbMobileDatabaseAuthenticatable < Authenticatable 
    def valid? 
    # if we have headers with the facebook access key 
    !!request.headers["fb_access_token"] 
    end 

    def authenticate! 
    token = request.headers["fb_access_token"] 
    fbuser = FbGraph::User.me(token) 
    fbuser = fbuser.fetch 

    user = User.find_for_facebook_mobile_client(fbuser.email) 

    # this either creates a new user for the valid FB account, or attaches 
    # this session to an existing user that has the same email as the FB account 

    if !!user && validate(user) { true } 
     user.after_database_authentication 
     success!(user) 
    elsif !halted? || !user 
     fail(:invalid) 
     end 
     end 
    end 
    end 
end 

Warden::Strategies.add(:fb_database_authenticatable, 
         Devise::Strategies::FbMobileDatabaseAuthenticatable) 

在配置/初始化,添加以下devise.rb:

config.warden do |manager| 
    manager.default_strategies(:scope => :user).unshift :fb_database_authenticatable 
    end 

爲了讓您無論是創建一個用戶或發現基礎上,FB電子郵件的現有用戶,添加下面給您的用戶模型:

def self.find_for_facebook_mobile_client(fb_email) 
    if user = User.where(:email => fb_email).first 
     user 
    else 
     User.create!(:email => fb_email, :password => Devise.friendly_token[0,20]) 
    end 
    end 

我不認爲fb_database_authenticatable是一個準確的名字,但我會離開,作爲一個練習留給讀者。另一個運動是高速緩存/存儲FB訪問令牌,也許避免RT與每個呼叫到FB。你應該注意的是,如果你在兩邊,我相信大部分人會不願意做FB驗證從移動應用和Rails應用程序的訪問令牌會有所不同。這可能會影響您的緩存方案。

我認爲,做它 - 快樂編碼。

+2

一些需要注意的:基本權限使用FB帳戶不要提供電子郵件地址。你需要明確地詢問用戶這個權限。 – beeudoublez

+0

好一點@beeudoublez,這正是我在我的應用程序一樣。 – Matt

0

如果您在Xcode 4.3.2 設置請求頭,你可以使用:

[request setValue:@"12345" forHTTPHeaderField:@"fbaccesstoken"]; 

,但你不能使用:

[request setValue:@"12345" forHTTPHeaderField:@"fb_access_token"]; // does NOT get set