Login do Linkedin OAuth2 para Rails

Há uma grande joia para autenticação com o nome do Linked: omniauth-linkedin-oauth2

Havia um problema com a gema original, então eu bifurquei e ajustei, então fique à vontade para fazer um fork ou usar a minha.

Criar aplicativo Linkedin

Em primeiro lugar, acesse https://www.linkedin.com/developer/apps e crie um aplicativo para autenticação.

Observação importante sobre a configuração do URL:

Você deve configurar urls de retorno de chamada para cada ambiente no aplicativo Linkedin para que os retornos de chamada funcionem corretamente.

Para desenvolvimento:

http://appname.dev/auth/linkedin/callback

Para produção:

https://appname.com/auth/linkedin/callback

1. Comece adicionando a gema

gem 'omniauth-linkedin-oauth2', git: 'https://github.com/Devato/omniauth-linkedin-oauth2.git'

2. Em seguida, configure o inicializador:

#config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider
:linkedin, ENV['LINKEDIN_CLIENT_ID'], ENV['LINKEDIN_CLIENT_SECRET'], secure_image_url: true
end

Agora vamos retornar ao URL de retorno de chamada. Este é o URL para onde um usuário será redirecionado dentro do aplicativo após a autenticação bem-sucedida e a autorização aprovada (a solicitação também conterá os dados e o token do usuário). Todas as estratégias OmniAuth esperam que o URL de retorno de chamada seja igual a “/ auth /: provedor / retorno de chamada”. : o provedor obtém o nome da estratégia (“twitter”, “facebook”, “linkedin”, etc.) conforme listado no inicializador.

3. Adicione as rotas

#config/routes.rb
get '/auth/:provider/callback', to: 'oauth#callback', as: 'oauth_callback'
get '/auth/failure', to: 'oauth#failure', as: 'oauth_failure'

4. Um link para enviar a solicitação ao Linkedin (obviamente ainda não funcionará).

= link_to 'Register with Linkedin', '/auth/linkedin' 

5. Prepare-se para armazenar os dados

Você pode configurar o armazenamento de dados da maneira que desejar. Criei um modelo separado para guardar tudo. Esta é a migração:

class CreateOauthAccounts < ActiveRecord::Migration
def change
create_table
:oauth_accounts do |t|
t
.belongs_to :user, index: true, foreign_key: true
t
.string :provider
t
.string :uid
t
.string :image_url
t
.string :profile_url
t
.string :access_token
t
.text :raw_data
t
.timestamps null: false
end
end
end

6. Processe o retorno de chamada.

Eu gerei um Oauthcontrolador para manter as coisas separadas:

#app/controllers/oauth_controller.rb
class OauthController < ApplicationController

def callback
begin
oauth
= OauthService.new(request.env['omniauth.auth'])
if oauth_account = oauth.create_oauth_account!
...
redirect_to
Config.provider_login_path
end
rescue => e
flash
[:alert] = "There was an error while trying to authenticate your account."
redirect_to register_path

end
end

def failure
flash
[:alert] = "There was an error while trying to authenticate your account."
redirect_to register_path

end

end

Você notará que existem dois métodos para lidar com a resposta do LinkedIn. callbacke failure. O retorno de chamada está processando os dados e criando os registros conforme necessário. é um serviço personalizado usado para realmente processar os dados.request.env['omniauth.auth']OauthService

7. O serviço que processa dados de retorno de chamada

Passei esse processamento para uma classe de serviço para manter tudo organizado:

#app/services/oauth_service.rb
class OauthService
attr_reader
:auth_hash

def initialize(auth_hash)
@auth_hash = auth_hash
end

def create_oauth_account!
unless oauth_account = OauthAccount.where(uid: @auth_hash[:uid]).first
oauth_account
= OauthAccount.create!(oauth_account_params)
end
oauth_account

end

private

def oauth_account_params
{ uid: @auth_hash[:uid],
provider
: @auth_hash[:provider],
image_url
: @auth_hash[:info][:image],
profile_url
: @auth_hash[:info][:urls][:public_profile],
raw_data
: @auth_hash[:extra][:raw_info].to_json }
end

end

Existem muitas maneiras diferentes de fazer isso, mas parecia certo e era bastante simples de testar.

ADICIONE COBERTURA DE TESTE DE RSPEC

Existem algumas nuances de teste desse processo, e aqui está o que funcionou na configuração do mocking:

1. Configurar macro para simular a resposta

#spec/support/omniauth_macros.rb
module OmniauthMacros
def mock_auth_hash
# The mock_auth configuration allows you to set per-provider (or default)
# authentication hashes to return during integration testing.
OmniAuth.config.mock_auth[:linkedin] = OmniAuth::AuthHash.new({
'provider' => 'linkedin',
'uid' => '123545',
'info' => {
'name' => 'mockuser',
'image' => 'mock_user_thumbnail_url',
'first_name' => 'john',
'last_name' => 'doe',
'email' => 'john@doe.com',
'urls' => {
'public_profile' => 'http://test.test/public_profile'
}
},
'credentials' => {
'token' => 'mock_token',
'secret' => 'mock_secret'
},
'extra' => {
'raw_info' => '{"json":"data"}'
}
})
end
end

2. Inclua esta macro em sua configuração RSpec:

#spec/rails_helper.rb
RSpec.configure do |config|
config
.include(OmniauthMacros)
end

Então, abaixo do bloco de configuração, defina OmniAuth para o modo de teste:

OmniAuth.config.test_mode = true

3. Adicionar especificação de solicitação:

#spec/requests/registration_spec.rb

require "rails_helper"

describe
"home#register as a provider", :type => :request do

it
"redirects to oauth#callback" do
get '/auth/linkedin'
expect
(response).to redirect_to(oauth_callback_path(:linkedin))
end

end

Como OmniAuthestá em modo de teste, ele deve redirecionar para retorno de chamada.

4. Especificação do OauthController:

#spec/controllers/oauth_controller_spec.rb

require 'rails_helper'

describe
OauthController, type: :controller do

before
(:each) do
mock_auth_hash

request
.env['omniauth.auth'] = OmniAuth.config.mock_auth[:linkedin]
end

after
(:each) do
OmniAuth.config.mock_auth[:linkedin] = nil
end

describe
'GET #callback' do
it
'expects omniauth.auth to be be_truthy' do
get :callback, provider: :linkedin
expect
(request.env['omniauth.auth']).to be_truthy
end

it
'completes the registration process successfully' do
get :callback, provider: :linkedin
expect
(page).to redirect_to Config.provider_login_path
end

it
'creates an oauth_account record' do
expect
{
get :callback, provider: :linkedin
}.to change { OauthAccount.count }.by(1)
end

end

end

Você notará a chamada mock_auth_hashe a configuração de prepara os dados de simulação para teste.request.env['omniauth.auth']

Esses testes básicos garantem que o mock esteja funcionando corretamente, que sejamos redirecionados para a rota adequada e que o OauthAccountregistro tenha sido criado corretamente.

Existem muitas maneiras diferentes de alcançar os mesmos resultados, mas foi isso que funcionou bem para nós e, esperançosamente, é uma boa referência para qualquer pessoa necessária para realizar as mesmas coisas.