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.
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
Buen punto @beeudoublez, eso es exactamente lo que hice en mi aplicación. – Matt