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/callback
config/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 é:
- Quando um usuário faz login, procure as autorizações existentes para essa conta externa.
- Crie um usuário se nenhuma autorização for encontrada.
- 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 create
ação em SessionsController
para 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.