【问题标题】:How to fix SSL error thrown by omniauth LinkedIn如何修复omniauth LinkedIn引发的SSL错误
【发布时间】:2021-08-16 14:04:29
【问题描述】:

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

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

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

  1. 设计~> 4.8.0
  2. omniauth-linkedin-oauth2 ~> 1.0.0
  3. omniauth ~> 2.0.4

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

【问题讨论】:

    标签: ruby-on-rails devise linkedin omniauth omniauth-linkedin


    【解决方案1】:

    为您提供的有关 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:通过添加thin gem 创建 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一段时间后这个状态消失就ok了!

    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
    

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

    <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>
    

    成功的画面:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-01
      • 2018-01-15
      • 2018-11-25
      • 1970-01-01
      • 2022-06-13
      • 2012-02-08
      • 2020-10-27
      相关资源
      最近更新 更多