7

Abbiamo un'installazione di app per rails che utilizza l'omnio & per consentire l'accesso tramite l'autenticazione di Facebook. Abbiamo anche un'app mobile che attualmente utilizza l'autenticazione http per accedere all'app rails passando la password del nome utente & o passando il token di autenticazione http. Tutto funziona alla grande finora.Come utilizzare l'autenticazione http in oggetto con un token omniauth opzionale come token di autenticazione

L'app mobile ha anche la possibilità di autenticarsi con Facebook stesso e ricevere il token utente Facebook direttamente tra sé e Facebook.

Vorrei colmare questa lacuna in modo che se l'utente ha effettuato il login dall'app mobile tramite Facebook e ha il proprio token facebook, consentire che il token di Facebook venga utilizzato come autenticazione sull'app rails come se avessero ricevuto da Facebook tramite il browser.

Il risultato finale sarebbe che l'applicazione mobile può accedere un utente in via:

1) username/password o 2) http token di autenticazione o 3) omniauth (facebook) Token

Inoltre, nel caso di 3), se l'utente non esiste ancora nell'app per rails, dovrebbe creare l'utente - facendo così ora già con l'autenticazione lato browser in modo che non ci sia più nulla da fare.

Come posso ottenere questo risultato all'interno del costrutto?

risposta

10

Ho appena fatto questo, ma non ho mai visto una soluzione end-to-end.

Questo indirizzo punto 3. 1 & 2 sono facilmente realizzabili con elaborati e documentati altrove.

Non troppo difficile aggiungere l'autenticazione FB alla tua app Web, le istruzioni sono su github per omniauth e omniauth-facebook.

Credo che il seguente si erge da solo, senza fare l'integrazione omniauth-facebook, se si vuole fare in questo modo. Questo è simile ad altri approcci là fuori. La mia idea era di tentare di usare il modello di idea il più vicino possibile.

Avrai bisogno della gemma fb_graph.

Sul client mobile, si autentica correttamente con FB e si inserisce il token di accesso restituito nell'intestazione delle richieste http. Ho usato l'intestazione fb_access_token. Proprio come l'autenticazione di base, ti consigliamo di inviarlo su SSL per evitare lo sniffing del token. L'utilizzo dell'intestazione mi consente di scambiare l'autenticazione di base e l'autenticazione FB senza modificare le richieste, ma se preferisci puoi utilizzare un parametro.

Questa soluzione implementa una strategia di guardia che si basa sulla strategia di autenticazione Authenticatable. La differenza qui è il fatto che questa strategia utilizza un'intestazione HTTP chiamata fb_access_token contenente la stringa token di accesso di Facebook che è stata recuperata utilizzando l'applicazione mobile.

Una volta saputo questo, il codice è piuttosto semplice.

In un file, nella directory config/initializers, aggiungere quanto segue. Mi è capitato di chiamare il mio 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) 

in config/inizializzatori, aggiungere il seguente al devise.rb:

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

Per consentire di creare un utente o di trovare un utente esistente in base alla e-mail FB, aggiungere il segue al proprio modello utente:

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 

non credo fb_database_authenticatable è un nome preciso, ma lascio che come esercizio per il lettore. Un altro esercizio consiste nella memorizzazione nella cache/memorizzazione del token di accesso FB, e forse evitando il RT in FB con ogni chiamata. Dovresti notare che il token di accesso dall'app per dispositivi mobili e dall'app per i binari sarà diverso se esegui l'autenticazione FB su entrambi i lati, il che sospetto che la maggior parte delle persone vorrà fare. Ciò probabilmente influisce sul tuo schema di caching.

Penso che lo faccia, felice codifica.

+2

cosa da notare: Le autorizzazioni di base per l'utilizzo di un account di FB non fornire l'indirizzo email Dovrai chiedere esplicitamente all'utente questa autorizzazione. – beeudoublez

+0

Buon punto @beeudoublez, è esattamente ciò che ho fatto nella mia app. – Matt

0

Se si sta impostando gli header di richiesta in Xcode 4.3.2 si potrebbe usare:

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

ma non è possibile utilizzare:

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