1. Introdução
O Oauth 2 é um protocolo que fornece um fluxo específico de autorização para aplicações web, desktop e mobile. Dessa forma, o usuário consegue ter acesso a aplicações de terceiros sem expor suas credenciais, apenas delegando a sua autenticação ao serviço que hospeda a conta dele, como por exemplo o Facebook, Github ou Twitter.
A imagem abaixo ilustra o fluxo e os papéis definidos pelo Oauth2:
1 - O usuário da aplicação (Resource Owner) solicitará acesso a nossa aplicação (Client Application) através do nosso provider ao invés de fazer o login utilizando o formulário.
2- Como resposta, ele será redirecionado para o servidor de autorização (Authorization Server) para permitir acesso aos seus dados naquele determinado provider
3 - Após permitir o acesso, nossa aplicação receberá um token de acesso para que possa consumir os dados do servidor de recurso (Resource Server)
2. Exemplificando
Para ficar mais claro, vamos implementar um exemplo utilizando o Facebook como fornecedor para logarmos na nossa aplicação Rails.
Vamos utilizar as gems Devise e omniauth-facebook para implementar a autenticação. Siga as instruções de instalação dessas gems seguindo a documentação linkada acima.
O primeiro passo é adicionar dois campos ao nosso model de usuário (User): provider
e uid
. Fazemos isso criando uma migration:
class AddOmniauthToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :provider, :string
add_column :users, :uid, :string
end
end
A coluna provider
irá armazenar qual o nome do fornecedor de serviço que está sendo utilizado para fazer a autenticação. No nosso exemplo será 'Facebook'
A coluna uid
irá armazenar um identificador único daquele usuário em dado provider. No nosso exemplo, o Facebook ID do usuário
Depois, no config/initializers/devise
, declaramos o provider
: config.omniauth :facebook, ENV["APP_ID"], ENV["APP_SECRET"]
.
2.1 Gerando as chaves
Para gerar o APP_ID e o APP_SECRET acesse developers.facebook.com
e faça seu login, caso já não esteja logado.
Vá em Meus aplicativos e depois clique em Criar Aplicativo.
Escolha Criar experiências conectadas e clique em Continuar.
Preencha o campo Nome de exibição do aplicativo com o nome do aplicativo e clique em Criar aplicativo. Após isso vá em Login Facebook e clique em Configurar.
Na tela seguinte, escolhemos a opção Web.
O campo da URL do site, preencha com http://localhost:3000
e clique em Save.
Vale lembrar que é importante verificar no menu superior, se está em Modo de Desenvolvimento.
No menu lateral vá em Configurações -> Básico e lá você terá acesso ao seu APP_ID e APP_SECRET.
Copie esses dados e os adicione no seu arquivo .env
na raiz do projeto. Eles devem ficar como no trecho de código abaixo:
APP_ID=1560871004116268
APP_SECRET=3912830dad8jU987987DS215
Lembrando que não se deve enviar o arquivo .env para repositórios como Github, pois suas chaves ficarão públicas e outro usuário poderia usá-las se passando por você.
2.2 Configurando
No seu model de usuário, adicione :omniauthable, omniauth_providers: %i[facebook]
na configuração do Devise.
```
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:omniauthable, omniauth_providers: %i[facebook]
end
Após esse passo, se já tiver adicionado o `devise_for :user` no seu arquivo de rotas, é gerada uma rota `user_facebook_omniauth_callback_path` que será utilizada como *callback* após o login pelo Facebook.
Iremos sobrescrever o controller padrão do devise **omniauth_callbacks**, para que possamos implementar a lógica necessária para tratarmos os dados de callback após logarmos.
Faremos isso alterando o arquivo `config/routes` como no código abaixo:
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' } ```
Depois de alterar a rota precisaremos criar o controller em app/controllers/users/omniauth_callbacks_controller.rb
.
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token, only: :facebook
def facebook
@user = User.from_omniauth(request.env["omniauth.auth"])
if @user.persisted?
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"].except(:extra)
redirect_to new_user_registration_url
end
end
def failure
redirect_to root_path
end
end
Nesse controller temos alguns pontos a destacar:
1) Toda informação retornada pelo Facebook através dessa autenticação está disponível na Hash request.env["omniauth.auth"]
.
2) Quando um usuário válido é encontrado, ele pode logar com dois métodos distintos do Devise: o sign_in
ou sign_in_and_redirect
.
3) Uma Flash Message também poderá ser usada nas mensagens padrão do Devise, fica a seu critério.
4) No caso do usuário não estiver persistindo, nós armazenamos os dados da autenticação na sessão e então o direcionamos para a página de registro.
Após criar o controller precisamos ir no nosso model de usuário e criar o método from_omniauth
no arquivo app/models/user.rb
. Esse método tentará encontrar um usuário existente a partir do provider
que é passado e do uuid
. Se o usuário não for encontrado um novo será criado com uma senha aleatória.
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:omniauthable, omniauth_providers: %i[facebook]
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0, 20]
end
end
end
Por fim para criar o botão de logout adicionamos a rota:
delete 'sign_out', :to => 'devise/sessions#destroy', :as => :destroy_user_session
Ficando, por fim, assim:
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' } do
delete 'sign_out', :to => 'devise/sessions#destroy', :as => :destroy_user_session
end
Depois disso, deve ser possível realizar o login na sua aplicação usando o Facebook tornando mais ágil a utilização do seu site/serviço pelo usuário.
Além do Facebook, também existem diversas alternativas para fazer o processo de autenticação do seu site, dentre elas o Twitter, Google, LinkedIN e a lista não acaba por aí.