使用omniauth和Facebook验证用户是否为rails API?

idr*_*ale 47 authentication facebook ruby-on-rails omniauth

我正在构建一个Rails API,并已成功为用户构建了一种使用Omniauth Identity进行身份验证的方法.

我们只需从客户端发送到auth/identity/callback,传入auth_key和密码.
然后,服务器返回一个门卫令牌,用户随后使用该门牌令牌来访问应用程序并识别自己.

该图说明了这一点:

客户服务器关系

我们现在想要从客户端实现Facebook登录,但在理论上和实际上都无法使其正常工作.

在一个简单的带有Omniauth身份的Rails应用程序上,你只需要调用auth/facebook,但是如果我们在客户端中放置一个链接,它会调用服务器,然后服务器会记录:

INFO -- omniauth: (facebook) Request phase initiated.

该应用程序在Facebook中正确设置了ID和密码,因此登录提示可能会返回到服务器?

虽然链接身份验证我很困惑.任何帮助感激不尽!

在此输入图像描述

a14*_*14m 49

我找到的最好的方法(在这个问题上被困一段时间后)是手动完成omniauth2(特别是在我的情况下使用satellizer angular plugin)...

我将讨论Facebook的解决方案,因为它是我的情况,但一切都适用于任何其他提供商.

首先你必须知道omniauth2是如何工作的(正如这里为人类所记录的那样)......

  1. 客户端:打开一个弹出窗口供用户进行身份验证.
  2. 客户:登录(如有必要),然后授权该应用程序.
  3. 客户端:成功授权后,弹出窗口将重定向回您的应用程序.使用code (授权代码)查询字符串参数

重定向回网址必须与您的前端应用网址匹配,而不是后端网址,并且必须在您的Facebook应用配置中指定

  1. 客户端:code参数被发送回打开弹出窗口的父窗口.
  2. 客户:父窗口关闭弹出并发送POST请求backend/auth/facebookcode参数.
  3. 服务器: code(授权代码)可以交换access token

这里详细描述了如何来交换code一个access-tokenFacebook开发文档

  1. 服务器:使用access-token步骤6中检索的内容检索用户的信息.

  2. VOILA你有自己的用户,你可以合并/创建帐户/链接​​其他oauth提供商/等.但请记住,用户可以撤销一些权限(如电子邮件,Facebook支持撤销一些权限)...


(说得够多,给我看一些代码)

首先,您必须将HTTParty gem添加到Gemfile中

gem 'httparty'  # Makes http fun again (http client)
Run Code Online (Sandbox Code Playgroud)

我已经添加了这个包含步骤(6,7和8)流程的要点,这些步骤是最有问题的步骤,并且几乎没有记录在任何地方.

要点出口2主要方法:

Omniauth::Facebook.authenticate(authorization_code)
Run Code Online (Sandbox Code Playgroud)

用于通过facebook验证用户并返回user_info,long_live_access_token(有效期为60天)

Omniauth::Facebook.deauthorize(access_token)
Run Code Online (Sandbox Code Playgroud)

用于取消授权/撤销facebook上的access_token和应用程序权限...

这用于我的特殊要求,当用户撤销facebook登录时请求的电子邮件权限时...我们撤销整个应用程序权限...这将在下次登录时提示用户,就好像这是他第一次登录(不需要)转到Facebook应用程序并手动撤销应用程序).​​..

这是它在控制器中的使用方式

user_info, access_token = Omniauth::Facebook.authenticate(params['code'])
if user_info['email'].blank?
  Omniauth::Facebook.deauthorize(access_token)
end
Run Code Online (Sandbox Code Playgroud)

就是这样......现在如果你对实现的内部感兴趣......这里是gist中的代码.(作为参考添加)随意分叉,编辑,帮助使其更好.

require 'httparty'

module Omniauth
  class Facebook
    include HTTParty

    # The base uri for facebook graph API
    base_uri 'https://graph.facebook.com/v2.3'

    # Used to authenticate app with facebook user
    # Usage
    #   Omniauth::Facebook.authenticate('authorization_code')
    # Flow
    #   Retrieve access_token from authorization_code
    #   Retrieve User_Info hash from access_token
    def self.authenticate(code)
      provider = self.new
      access_token = provider.get_access_token(code)
      user_info    = provider.get_user_profile(access_token)
      return user_info, access_token
    end

    # Used to revoke the application permissions and login if a user
    # revoked some of the mandatory permissions required by the application
    # like the email
    # Usage
    #    Omniauth::Facebook.deauthorize(access_token)
    # Flow
    #   Send DELETE /me/permissions?access_token=XXX
    def self.deauthorize(access_token)
      options  = { query: { access_token: access_token } }
      response = self.delete('/me/permissions', options)

      # Something went wrong most propably beacuse of the connection.
      unless response.success?
        Rails.logger.error 'Omniauth::Facebook.deauthorize Failed'
        fail Omniauth::ResponseError, 'errors.auth.facebook.deauthorization'
      end
      response.parsed_response
    end

    def get_access_token(code)
      response = self.class.get('/oauth/access_token', query(code))

      # Something went wrong either wrong configuration or connection
      unless response.success?
        Rails.logger.error 'Omniauth::Facebook.get_access_token Failed'
        fail Omniauth::ResponseError, 'errors.auth.facebook.access_token'
      end
      response.parsed_response['access_token']
    end

    def get_user_profile(access_token)
      options = { query: { access_token: access_token } }
      response = self.class.get('/me', options)

      # Something went wrong most propably beacuse of the connection.
      unless response.success?
        Rails.logger.error 'Omniauth::Facebook.get_user_profile Failed'
        fail Omniauth::ResponseError, 'errors.auth.facebook.user_profile'
      end
      response.parsed_response
    end


    private

    # access_token required params
    # https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.3#confirm
    def query(code)
      {
        query: {
          # The authorization_code we want to exchange for the access_token
          code: code,
          # This must match the redirectUrl registerd in the facebook app.
          # You can save it to ENV['WEB_APP_URL'] if you have multiple facebook apps for development and testing
          # so you can support testing app on development and production app on production env.
          redirect_uri: "http://localhost:9000/",
          client_id: ENV['FB_APP_ID'], # Facebook appId
          client_secret: ENV['FB_APP_SECRET'], # Facebook app secret (must not exist on front-end app for security)
        }
      }
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

这是另一个实现oauth for instagram的nodejs教程,帮助我了解oauth2是如何工作的(添加供参考)

  • 我一直在寻找这样的东西几个小时,谢谢! (2认同)