Autenticação Rails usando Facebook

Nota : Este é um post atualizado baseado no incrível de RailsRumble e Intridea.

Digite OmniAuth

A primeira etapa é adicionar OmniAuth e a estratégia oauth que você deseja (neste caso, Facebook) ao seu Gemfile:

# Gemfile
gem
'omniauth'
gem
'omniauth-facebook'

Agora precisamos criar um inicializador para usar o middleware OmniAuth:

# config/intitializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider
:facebook, 'APP_ID', 'APP_SECRET'
end

Para separar os logins de teste e produção (também depuração), você pode listar diferentes credenciais para estes dois ambientes:

# config/intitializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
if Rails.env.development?
provider
:facebook, 'STAGING_APP_ID', 'STAGING_APP_SECRET'
elsif Rails.env.production?
provider
:facebook, 'PRODUCTION_APP_ID', 'PRODUCTION_APP_SECRET'
end
end

Na verdade, você já fez bastante. Tente executar seu aplicativo com o servidor rails e navegue para / auth / twitter, / auth / facebook ou / auth / linkedin. Você deve (assumindo que configurou os aplicativos com os respectivos provedores corretamente) ser redirecionado para o site apropriado e solicitado a fazer o login.

Lidando com o retorno de chamada

Após a confirmação, você deve ser redirecionado de volta e obter um erro de roteamento do Rails de . Então, vamos adicionar uma rota! Além disso :/auth/yourprovider/callbackconfig/routes.rb

# config/routes.rb
match
'/auth/:provider/callback', :to => 'sessions#create', via: :get

Mas, claro, isso aponta para um controlador inexistente, então vamos criá-lo também:

$ rails generate controller Sessions create

Agora, em nosso sessions_controller.rb, vamos adicionar um pouco de código:

# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def create
render
:text => request.env['omniauth.auth'].inspect
end
end

Se você iniciar o aplicativo novamente e passar pelo processo de autenticação, deverá ver um hash que inclui muitas informações sobre o usuário, em vez de um erro de roteamento. Estamos a caminho!

Autorizações e usuários

Uma das coisas boas do OmniAuth é que ele não presume como você deseja lidar com as informações de autenticação, ele apenas examina as partes difíceis para você. Queremos que os usuários possam fazer login usando um ou vários serviços externos, então, na verdade, vamos separar os usuários das autorizações. Vamos criar modelos simples de autorização e usuário agora.

$ rails g model Authorization provider uid user:references
$ rails g model
User email

Isso cria os modelos de que precisamos com as migrações apropriadas. Observe que o modelo de usuário não precisa conter nenhuma informação sobre os provedores de autenticação porque vamos modelar isso por meio de um relacionamento com o modelo de autorização. Configure seus modelos assim:

# app/models/user.rb
class User < ActiveRecord::Base
has_many
:authorizations
validates
:email, presence: true
end

# app/models/authorization.rb
class Authorization < ActiveRecord::Base
belongs_to
:user
validates
:user_id, :uid, :provider, presence: true
validates_uniqueness_of
:uid, :scope => :provider
end

Aqui, estamos modelando relacionamentos muito simples e garantindo que a Autorização tenha um provedor (“facebook”) e um uid (o ID do Facebook, ou seja:) 123456789123456. A seguir, conectaremos esses modelos ao nosso controlador para criar um processo de login real.

Inscrevendo-se / Em

Uma das coisas boas sobre a autenticação externa é que você pode reduzir o processo de inscrição e login em uma única etapa. O que faremos aqui é:

  1. Quando um usuário faz login, procure as autorizações existentes para essa conta externa.
  2. Crie um usuário se nenhuma autorização for encontrada.
  3. Adicione uma autorização a um usuário existente se o usuário já estiver conectado.

Vamos trabalhar para trás para essa funcionalidade adicionando o código que queremos ter ao controlador. Modifique a createação em SessionsControllerpara ficar assim:

# app/controllers/sessions_controller.rb
def create
auth
= request.env['omniauth.auth']
unless @auth = Authorization.find_from_hash(auth)
# Create a new user or add an auth to existing user, depending on
# whether there is already a user signed in.
@auth = Authorization.create_from_hash(auth, current_user)
end
# Log the authorizing user in.
self.current_user = @auth.user

render
:text => "Welcome, #{current_user.email}."
end

Agora vamos implementar alguns desses métodos. Primeiro, adicionando alguns métodos de classe à autorização:

# app/models/authorization.rb
def self.find_from_hash(hash)
find_by_provider_and_uid
(hash['provider'], hash['uid'])
end

def self.create_from_hash(hash, user = nil)
user
||= User.create_from_hash!(hash)
Authorization.create(user: user, uid: hash['uid'], provider: hash['provider'])
end

Agora precisamos adicionar o método referenciado acima à classe User:

# app/models/user.rb
def self.create_from_hash!(hash)
create
(email: hash.info.email)
end

Finalmente, precisamos adicionar alguns auxiliares ao ApplicationController para lidar com o estado do usuário:

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protected

def current_user
@current_user ||= User.find_by_id(session[:user_id])
end

def signed_in?
!!current_user
end

helper_method
:current_user, :signed_in?

def current_user=(user)
@current_user = user
session
[:user_id] = user.id
end
end

Voila! Agora, um usuário pode entrar usando qualquer uma de suas contas e um usuário será automaticamente obtido ou criado.