9

我正在尝试在 rails 5.2 应用程序中通过 LinkedIn 设置身份验证,同样我指的是 devise 提供的文档,但我收到以下错误:

ERROR -- omniauth: (linkedin) Authentication failure! Connection reset by peer: Faraday::SSLError, Connection reset by peer

我已经使用以下 gem 添加了这些配置

  1. 设计〜> 4.8.0
  2. omn​​iauth-linkedin-oauth2 ~> 1.0.0
  3. 全域认证 ~> 2.0.4

我什至尝试在包含有效 SSL 证书的生产服务器的活动域上运行,但仍然抛出相同的错误。

4

1 回答 1

0

为您提供有关LinkedIn的一些信息:

LinkedIn no longer supports the JavaScript SDK. The recommended approach is to use OAuth 2.0 and LinkedIn's Auth APIs.

和:

LinkedIn does not support TLS 1.0. Support for TLS 1.1 has been marked for deprecation starting 02/01/2020. Please use TLS 1.2 when calling LinkedIn APIs. All API requests to api.linkedin.com must be made over HTTPS. Calls made over HTTP will fail.

Step 1:为Javascript库添加Jquery,运行命令:

$ yarn add jquery

然后,设置 config/webpack/environment.js 的内容:

const { environment } = require('@rails/webpacker')
const webpack = require('webpack')
environment.plugins.prepend('Provide',
 new webpack.ProvidePlugin({
   $: 'jquery/src/jquery',
   jQuery: 'jquery/src/jquery'
 })
)
module.exports = environment

Step 2: 通过添加thingem创建 ssl 连接

gem 'thin'
$ bundle install

编辑config/application.rb并添加:

config.force_ssl = true

在项目命令行中,键入:

$ openssl genrsa 2048 > host.key
$ chmod 400 host.key
$ openssl req -new -x509 -nodes -sha256 -days 365 -key host.key -out host.cert

在这些命令之后将创建两个文件:host.keyhost.cert. 然后运行:

$ thin start --ssl --ssl-key-file=./host.key --ssl-cert-file=./host.cert

它将在默认地址运行项目:https://0.0.0.0:3000。如果你想在 https://localhost:3000 上运行,只需输入:

$ thin start -a localhost --ssl --ssl-key-file=./host.key --ssl-cert-file=./host.cert

Step 3:创建Linkedin oauth2 应用程序。

转到链接:https://www.linkedin.com/developers/

单击按钮Create app,然后将信息填写到应用名称、LinkedIn 页面(必须通过自定义页面完成)、应用徽标、条款复选框。然后单击创建应用程序以注册您的应用程序。

在设置选项卡上,设置应用程序的域,我使用 localhost 运行,所以我将设置https://localhost:3000.

在 Auth 选项卡中,将 Client ID 和 Client Secret 保存到config/application.yml(记得在此之前运行命令$ bundle exec figaro install),如下所示:

LINKEDIN_APP_ID: 86g3...sfjm
LINKEDIN_APP_SECRET: OKnb...jzSL

然后为您的应用编辑、输入和保存部分授权重定向 URL:

https://localhost:3000/auth/linkedin/callback

检查可在此页面中使用的范围!我的是r_emailaddress r_liteprofile

在产品选项卡上,选择Sign In with LinkedIn,状态将更改为Review in progress。如果刷新 F5 一段时间后此状态消失,则一切正常!

Step 4:像我一样设置所有代码。简单config/routes.rb

Rails.application.routes.draw do
  devise_for :users, :controllers => { :omniauth_callbacks => "omniauth_callbacks" } 

  get '/auth/linkedin/callback', to: "linkedin#callback"
  post '/auth/linkedin/url', to: "linkedin#popup"
  post '/auth/linkedin/token', to: "linkedin#get_token"
  post '/auth/linkedin/info', to: "linkedin#get_info"
  post '/auth/linkedin/out', to: "linkedin#stop"
  root to: "linkedin#home"
end

使用内容创建app/controllers/linkedin_controller.rb

class LinkedinController < ApplicationController
  # Lib to get token
  require "uri"
  require "net/http"
  # Data variables set/get
  attr_accessor :client_id, :client_secret, :redirect_uri, :scope, :raise_error
  # Class variable with 2@
  @@token = ""
  # Return view linkedins/home page
  def home
    render 'linkedins/home'
  end
  # Call back from popup login window of LinkedIn site
  def callback
    Rails.logger.debug "Callback called! Params:"
    Rails.logger.debug params
    @code = params[:code]
    @state = params[:state]
    @redirect = '/auth/linkedin/callback'
    # Get token
    url = URI("https://www.linkedin.com/oauth/v2/accessToken")
    https = Net::HTTP.new(url.host, url.port)
    https.use_ssl = true
    request = Net::HTTP::Post.new(url)
    request["Content-Type"] = "application/x-www-form-urlencoded"
    host_uri = ENV['HOST']+@redirect
    request.body = "grant_type=authorization_code&code=#{@code}&client_id=#{ENV['LINKEDIN_APP_ID']}&client_secret=#{ENV['LINKEDIN_APP_SECRET']}&redirect_uri=#{host_uri}"

    response = https.request(request)
    Rails.logger.debug "response.read_body:"
    # Rails.logger.debug response.read_body
    r = JSON.parse(response.read_body)
    Rails.logger.debug r["access_token"]
    @@token = r["access_token"]

    render 'linkedins/callback'
  end
  # Config init values
  def start
    @client_id = ENV['LINKEDIN_APP_ID']
    @client_secret = ENV['LINKEDIN_APP_SECRET']
    @raise_error = 'true'
    @redirect = '/auth/linkedin/callback'
    @redirect_uri = ENV['HOST']+@redirect
    @scope = 'r_emailaddress r_liteprofile'
    @state = generate_csrf_token
  end
  # Return popup url for sign in by LinkedIn, method = POST
  def popup
    self.start
    @url = "https://www.linkedin.com/uas/oauth2/authorization?client_id=#{@client_id}&raise_errors=#{@raise_error}&redirect_uri=#{@redirect_uri}&response_type=code&scope=#{@scope}&state=#{@state}"
    # return @url
    render json: { status: 'Success', message: 'Load url for popup finished!', link: @url},status: :ok
  end
  # Get token of current account Linkedin logged
  def get_token
    Rails.logger.debug 'From get_token, @@token cache:'
    Rails.logger.debug @@token
    render json: { status: 'Success', message: 'Load token finished!', token: @@token},status: :ok
  end
  # Get basic info
  def get_info
    Rails.logger.debug 'From get_info!'
    # Create custom api linking
    fields = ['id', 'firstName', 'lastName', 'profilePicture']
    link = "https://api.linkedin.com/v2/me?projection=(#{ fields.join(',') })"

    url = URI(link)
    https = Net::HTTP.new(url.host, url.port)
    https.use_ssl = true
    request = Net::HTTP::Get.new(url)
    request["Authorization"] = "Bearer #{@@token}"
    response = https.request(request)
    Rails.logger.debug "From get_info, variable response:"
    Rails.logger.debug response
    r = JSON.parse(response.read_body)
    # r = JSON.parse(response.body)
    first_name = r['firstName']['localized']['en_US'].to_s
    last_name = r['lastName']['localized']['en_US'].to_s
    full_name = first_name + " " + last_name
    render json: { status: 'Success',message: 'Load link basic info finished!', name: full_name},status: :ok
  end
  # For logout LinkedIn, by method revoke
  def stop
    link = 'https://www.linkedin.com/oauth/v2/revoke'
    url = URI(link)
    https = Net::HTTP.new(url.host, url.port)
    https.use_ssl = true
    request = Net::HTTP::Post.new(url)
    request["Content-Type"] = "application/x-www-form-urlencoded"
    request.body = "client_id=#{ENV['LINKEDIN_APP_ID']}&client_secret=#{ENV['LINKEDIN_APP_SECRET']}&token=#{@@token}"
    response = https.request(request)
    Rails.logger.debug "Test logout linkedin!"
    render json: { status: 'Success',message: 'Log out finished!'},status: :ok
  end
  # Genereate random state
  def generate_csrf_token
    SecureRandom.base64(32)
  end
end

注意安装这些 gem,我们不需要任何 oauth2 链接库:

gem 'uri'
gem 'net-http'
$ bundle install

我们将通过此回调视图退出弹出式 LinkedIn 登录app/views/linkedins/callback.html.erb

<script>
  // Close this popup show from LinkedIn window open
  close();
</script>

创建这个主视图app/views/linkedins/home.html.erb

<p>Linkedin Login Home page</p>
<button id="linkedin-login" type="button">Login</button>
<p id="linkedin-informations">Token here!</p>

<button id="linkedin-logout" type="button">Logout</button>
<p id="linkedin-results">Results here!</p>

<script>
  $('#linkedin-login').on('click', function(e){
    // e.preventDefault()
    var url_popup = ""
    var ltoken = ""
    var lurl = ""
    $.post('/auth/linkedin/url', function(json) {
      console.log(json)
      url_popup = json.link
      if (url_popup != "") {
        console.log('Successful to load url popup!')
        const w = 600
        const h = 600
        const top = (screen.height - h) / 4, left = (screen.width - w) / 2
        
        var child = window.open(url_popup, "popupWindow", `width=${w}, height=${h}, top=${top}, left=${left}, scrollbars=yes`)
        
        function checkChild() {
          if (child.closed) {  
            clearInterval(timer);
            $.post('/auth/linkedin/token', function(json) {
              console.log('Load token link successful!')
              $('#linkedin-informations').html('Token is comming ...')
              ltoken = json.token
              console.log(json.token)
              $('#linkedin-informations').html(json.token)
            })
            $.post('/auth/linkedin/info', function(json) {
              console.log('Load info link successful!')
              $('#linkedin-results').html('Information is comming ...')
              console.log(json)
              $('#linkedin-results').html(`Your login account: ${json.name}`)
              
            }) 
          }
        }

        var timer = setInterval(checkChild, 500);
      }
    })
    
    
  })

  $('#linkedin-logout').on('click', function(e){
    e.preventDefault()
    $.post('/auth/linkedin/out', function(json) {
      console.log('Log out successful!')
      $('#linkedin-results').html(`You logged out!`)
    })
  })

</script>

成功画面: 在此处输入图像描述

于 2021-06-03T04:09:09.073 回答