0

到目前为止,我的网站一直在使用 Rails 直接生成的全栈视图,对于linkedin 身份验证,我使用了路由到 a 的 redirect_uriDevise::OmniauthCallbacksController来处理逻辑。

GET https://www.linkedin.com/oauth/v2/authorization?redirect_uri=my_devise_omniauth_callback_url

我想知道如何将其迁移到独立的 React 前端 + 独立的 Rails 服务器。React 应用程序应该“生成”一个linkedin 弹出窗口以进行授权,并等到所有授权过程完成后再关闭自身并在主窗口上继续注册。

我浏览过Linkedin OAuth 指南,我发现从批准连接到获取用户信息的过程相当漫长。我很高兴 Devise/Omniauth 为我在服务器端完成了大部分工作,我宁愿保持这种方式,而不是在前端编写该逻辑。

(顺便说一句,假设 Linkedin OAuth 流程类似于此答案中提到的 Google流程是否安全?)

我不确定这是否可以按照我在 React 应用程序上看到的方式完成(尤其是在linkedin 弹出窗口和主反应视图之间的数据通信)。同样据我了解,omniauth gemin rails 期望从 OAuth 提供程序接收一次性令牌,然后再查询提供程序两次(第一次交换访问令牌,第二次获取用户信息)。以下工作吗?

  • 假设我的 React Client 应用托管在client.example.com
  • 假设我的服务器 api 托管在api.example.com
  • React 应用程序打开一个弹出窗口,用于访问 Linkedin auth URI
    • (1) 直接指向 api.example.com 的重定向 uri
    • (2) client.example.com 上的 redirect_uri,然后我的 React 客户端必须将令牌转发到 api.example.com
  • 授权码在某种程度上到达了我的服务器api.example.com,该服务器获取访问码并从 Linkedin 检索用户数据。它返回浏览器一个identity_id可用于注册的
  • identity_id实际返回到弹出窗口,并转移回主 React 应用程序(如何?)
4

1 回答 1

2

我遇到了同样的问题,我找到了一个 hacky 但有趣的解决方案:-)
(我使用了所有 OAuth 逻辑deviseomniauth-linkedingems。)

在我的应用程序中,您可以开始填写表格,您需要先登录才能保存。我需要一种在不丢失表单数据和不重新加载页面的情况下记录用户的方法。

当用户访问该页面时,他会获得一个唯一的 uuid 来识别他。此 uuid 用于启动 websocket 连接,因此我可以稍后将数据直接推送到此选项卡。

我使用 javascript 在新选项卡中打开 LinkedIn OAuth,window.open()因此我可以使用window.close().

您可以将其他参数传递给 OAuth 身份验证,我传递了唯一的 uuid,因此我可以在身份验证成功时恢复它,并且使用此 uuid,我可以通过 websocket 发送消息来通知第一个选项卡(在我的应用程序中,我发送用户更新当前用户状态的信息)。

身份验证后,我将用户重定向到仅包含window.close().

在此处输入图像描述

在 Rails 中设置 LinkedIn OAuth

您将需要一个功能性的 Omniauth/Devise 身份验证工作。

omn​​iauth_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

用户.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

路线.rb

  devise_for :users, controllers: {
    omniauth_callbacks: "omniauth_callbacks",
    sessions: "users/sessions"
  }

现在,如果您访问/users/auth/linkedin,您将能够使用 LinkedIn OAuth 登录/创建用户。

Websocket 连接

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(带有设计和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>

希望这有帮助:)

于 2017-06-12T08:02:49.673 回答