Linkedin OAuth-аутентификация с помощью React Frontend + Rails API
До сих пор мой веб-сайт использовал представления полного стека, сгенерированные непосредственно Rails, и для проверки подлинности с помощью я использовал redirect_uri, перенаправленный на Devise::OmniauthCallbacksController
обращаться с логикой.
GET https://www.linkedin.com/oauth/v2/authorization?redirect_uri=my_devise_omniauth_callback_url
Мне интересно, как перенести это на автономный интерфейс React + автономный сервер Rails. Приложение React должно "вызвать" всплывающее окно для авторизации и дождаться завершения процесса авторизации, прежде чем закрыться и продолжить регистрацию в главном окне.
Я прошел через руководство по Linkedin OAuth, и я вижу, что путь от одобрения соединения до получения информации о пользователе довольно длинный. Я рад, что Devise/Omniauth выполняет большую часть работы для меня на стороне сервера, и я бы предпочел оставить это так, вместо того, чтобы кодировать эту логику во внешнем интерфейсе.
(Между прочим, безопасно ли предположить, что поток OAuth Linkedin похож на тот, который Google упоминал в этом ответе?)
Я не уверен, можно ли это сделать так, как я это вижу в приложении React (особенно обмен данными между всплывающим окном linkedin и основным видом реакции). Также из того, что я понимаю omniauth gem
Ожидается, что в rails получит одноразовый токен от поставщика OAuth, прежде чем он сможет запросить поставщика еще дважды (первый раз для обмена токеном доступа, второй раз для получения информации о пользователе). Будет ли следующая работа?
- Предположим, что мое приложение React Client размещено на
client.example.com
- Предположим, мой сервер API находится на
api.example.com
- Приложение React открывает всплывающие окна, которые используются для перехода на URI Linkedin Auth с
- (1) URI перенаправления, который будет указывать непосредственно на api.example.com
- (2) Redirect_uri на client.example.com, и мой клиент React должен будет перенаправить токен на api.example.com.
- Код авторизации доходит до моего сервера
api.example.com
, который получает код доступа и извлекает данные пользователя из Linkedin. Возвращает браузеруidentity_id
который можно использовать для регистрации identity_id
фактически возвращается во всплывающее окно и возвращается в основное приложение React (как?)
1 ответ
У меня была такая же проблема, и я нашел хакерское, но интересное решение:-)
(Я использую всю логику OAuth из devise
а также omniauth-linkedin
драгоценные камни.)
В моем приложении вы можете начать заполнять форму, и вам необходимо войти в систему, прежде чем сохранить ее. Мне нужен был способ войти в систему пользователя без потери данных формы и без перезагрузки страницы.
Когда пользователь посещает страницу, ему предоставляется уникальный идентификатор для его идентификации. Этот uuid используется для запуска соединения через веб-сокет, поэтому позже я могу перенести данные прямо на эту вкладку.
Я открываю LinkedIn OAuth в новой вкладке с помощью JavaScript window.open()
так что я могу закрыть эту вкладку с window.close()
,
Вы можете передать дополнительные параметры аутентификации OAuth, я передаю уникальный uuid, чтобы я мог восстановить его, когда аутентификация прошла успешно, и с помощью этого uuid я могу уведомить первую вкладку, отправив сообщение через websocket (в моем приложении я отправляю пользователю информация для обновления состояния с текущим пользователем).
После аутентификации я перенаправляю пользователя на страницу, содержащую только window.close()
,
Настройте LinkedIn OAuth в Rails
Вам понадобится функциональная проверка подлинности Omniauth/Devise.
omniauth_callback_controller.rb
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def linkedin
user = User.connect_to_linkedin(request.env["omniauth.auth"], current_user)
guest_guid = request.env["omniauth.params"]["guestGuid"]
if user.persisted?
ActionCable.server.broadcast("guest:#{guest_guid}", { user: UserSerializer.new(user).to_h })
sign_in(user)
redirect_to landing_home_index_path
end
end
end
user.rb
def self.connect_to_linkedin(auth, signed_in_resource = nil)
user = User.where(provider: auth.provider, linkedin_uid: auth.uid).first
if user
return user
else
registered_user = User.where(email: auth.info.email).first
if registered_user
return registered_user
else
user = User.create(lastname: auth.info.last_name, firstname: auth.info.first_name,
provider: auth.provider, linkedin_uid: auth.uid, email: auth.info.email,
linkedin_token: auth.credentials.token, linkedin_secret: auth.credentials.secret,
linkedin_picture: auth.extra.raw_info.pictureUrl, password: Devise.friendly_token[0, 20])
end
end
end
routes.rb
devise_for :users, controllers: {
omniauth_callbacks: "omniauth_callbacks",
sessions: "users/sessions"
}
Теперь, если вы посетите /users/auth/linkedin
Вы сможете войти / создать пользователя с LinkedIn OAuth.
Веб-сокет соединение
create_job_offer_channel.rb
class CreateJobOfferChannel < ApplicationCable::Channel
def subscribed
stream_from "guest:#{params[:guest]}"
end
def unsubscribed
end
def receive(data)
ActionCable.server.broadcast("guest:#{params[:guest]}", data)
end
end
create_job_offer.js.coffee
class window.CreateJobOffer
constructor: (params) ->
self = @
@channel = App.cable.subscriptions.create {
channel: "CreateJobOfferChannel", guest: params["guest"]
}, self
@onReceive = params["onReceive"] || null
received: (data) =>
@onReceive(data) if @onReceive
Реагировать на интерфейс
Ссылка на LinkedIn OAuth (с помощью devise и omniauth)
<div className="btn-linked-in">
<i className="fa fa-linkedin-square"></i>
<span onClick={() => open(`/users/auth/linkedin?guestGuid=${guestGuid}`)}>
Login with LinkedIn
</span>
</div>
Надеюсь это поможет:)