2011-08-29 22 views
7

Tenemos una configuración de aplicación de rieles que utiliza & omniauth para permitir el inicio de sesión a través de la autenticación de Facebook. También tenemos una aplicación móvil que actualmente utiliza la autenticación http para iniciar sesión en la aplicación Rails, ya sea al pasar la contraseña del nombre de usuario & o al pasar el token de autenticación HTTP. Todo esto funciona bien hasta ahora.Cómo usar la autenticación HTTP en el diseño con un token de omniauth opcional como el token de autenticación

La aplicación móvil también tiene la capacidad de autenticarse con Facebook y recibir el token de Facebook del usuario directamente entre sí y Facebook.

Me gustaría cerrar esta brecha para que si el usuario ha iniciado sesión desde la aplicación móvil a través de Facebook y tiene su token de Facebook, permita que el token de Facebook se utilice como autenticación en la aplicación de rails como si hubieran recibido desde Facebook a través del navegador.

El resultado final sería que la aplicación móvil puede registrar un usuario en via:

1) nombre de usuario/contraseña o 2) http autenticación de señales o 3) OmniAuth (facebook) contador

Además, en el caso de 3), si el usuario aún no existe en la aplicación de rieles, necesitaría crear el usuario, haciendo eso ahora con la autenticación del lado del navegador para que no haya nada más que hacer.

¿Cómo puedo lograrlo en la construcción del ingenio?

Respuesta

10

Simplemente hice esto, pero nunca vi una solución de principio a fin.

Este punto de direcciones 3. 1 & 2 se logra fácilmente con el dispositivo y se documenta en otro lugar.

No es muy difícil agregar autenticación FB a su aplicación web, las instrucciones están en github para omniauth y omniauth-facebook.

Creo que lo siguiente es independiente, sin hacer la integración omniauth-facebook, si quieres hacerlo de esa manera. Esto es similar a otros enfoques que existen. Mi idea era intentar usar el modelo de diseño lo más cerca posible.

Necesitarás la gema fb_graph.

En el cliente móvil, se autentica correctamente con FB y coloca el token de acceso devuelto en el encabezado de sus solicitudes http. Usé el encabezado fb_access_token. Al igual que la autenticación básica, querrá enviar esto a través de SSL para evitar olfatear el token. Usar el encabezado me permite intercambiar autenticación básica y autenticación de FB sin cambiar las solicitudes, pero puede usar un parámetro si lo prefiere.

Esta solución implementa una estrategia warden que se basa en la estrategia ideada de Warden Authenticatable. La diferencia aquí es el hecho de que esta estrategia utiliza un encabezado HTTP llamado fb_access_token que contiene la cadena de tokens de acceso de Facebook que se recuperó usando la aplicación móvil.

Una vez que sepa esto, el código es bastante sencillo.

En un archivo, en el directorio config/initializers, agregue lo siguiente. Casualmente llamé a la mía 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) 

En config/inicializadores, añada lo siguiente a devise.rb:

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

Para permitirle a cualquiera crear un usuario o encontrar un usuario existente basado en el correo electrónico FB, agregue el siguiente a su modelo de usuario:

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 

no creo fb_database_authenticatable es un nombre exacto, pero voy a dejar que como ejercicio para el lector. Otro ejercicio es almacenar en caché/almacenar el token de acceso FB, y quizás evitar el RT a FB con cada llamada. Debe tener en cuenta que el token de acceso de la aplicación móvil y la aplicación de rieles será diferente si realiza la autenticación de FB en ambos lados, lo cual sospecho que la mayoría de la gente querrá hacer. Esto probablemente afecte su esquema de almacenamiento en caché.

Creo que lo hace - happy coding.

+2

Algo a tener en cuenta: Los permisos básicos para utilizar una cuenta de FB no proporcione la dirección de correo electrónico. Deberá pedir explícitamente al usuario este permiso. – beeudoublez

+0

Buen punto @beeudoublez, eso es exactamente lo que hice en mi aplicación. – Matt

0

Si va a configurar los encabezados de solicitud en Xcode 4.3.2 puede usar:

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

pero no se puede utilizar:

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