使用omniauth和Facebook验证Rails API的用户身份? [英] Authenticate user using omniauth and Facebook for a rails API?

查看:58
本文介绍了使用omniauth和Facebook验证Rails API的用户身份?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建Rails API,并已成功构建了一种使用户可以使用Omniauth身份验证的方法.

I'm building a Rails API and have successfully built a way for a user to authenticate using Omniauth Identity.

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

We simply post to auth/identity/callback from the client, passing in an auth_key and password.
The server then returns a doorkeeper token that the users then uses from then on to access the app and identify themselves.

此图说明了这一点:

我们现在想从客户端实施Facebook登录,但是在理论上和实践上都很难使它生效.

We'd now like to implement a Facebook login from the client, but are having trouble making it work, both theoretically and practically.

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

On a simple Rails App with Omniauth Identity, you'd simply call auth/facebook, but if we put a link from this in the client, it calls the server and the server then logs:

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

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

The app is set up correctly in Facebook with an ID and Secret, so perhaps the log-in prompt is getting returned to the server?

通过链接身份验证,我感到困惑.任何帮助表示感谢!

I'm getting confused though chaining the authentication. Any help gratefully appreciated!

推荐答案

我发现最好的方法(在此问题上搁置了一段时间后)是进行omniauth2(在我的情况下,特别是使用

the best way I found (after being stuck for a while on this issue ) is to do your omniauth2 (specifically in my case using satellizer angular plugin) manually...

我将针对我的情况讨论适用于Facebook的解决方案,但一切都可以适用于任何其他提供商.

I'll discuss the solution for Facebook as it was my case, but everything could apply to any other provider.

首先,您必须了解omniauth2的工作原理(此处已记录为人类)...

first you have to know how omniauth2 works (as documented for humans here)...

  1. 客户端:打开一个弹出窗口,供用户进行身份验证.
  2. 客户端:登录(如有必要),然后授权该应用程序.
  3. 客户端:成功授权后,弹出窗口将重定向回您的应用.使用code (授权码)查询字符串参数
  1. Client: Open a popup window for user to authenticate.
  2. Client: Sign in (if necessary), then authorize the application.
  3. Client: After successful authorization, the popup is redirected back to your app. with the code (authorization code) query string parameter

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

  1. 客户端:code参数发送回打开弹出窗口的父窗口.
  2. 客户端:父窗口关闭弹出窗口,并使用code参数向backend/auth/facebook发送POST请求.
  3. 服务器::code(授权代码)已交换为 access token
  1. Client: The code parameter is sent back to the parent window that opened the popup.
  2. Client: Parent window closes the popup and sends a POST request to backend/auth/facebook with code parameter.
  3. Server: code (Authorization code) is exchanged for access token

此处详细描述了如何从

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

    1. Server: use the access-token retrieved in step 6 to retrieve the User's info.

    VOILA,您已经拥有自己的用户,可以与其他oauth提供商/等合并/创建帐户/链接​​.但请记住,用户可以撤消某些权限(例如电子邮件,facebook支持撤消某些权限)...

    VOILA you've got yourself a user you can merge/create account for/link with other oauth providers/etc. but bear in mind that user can revoke some of the permissions (like email, facebook supports revoking some of the permissions)...


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


    (enough talking, show me some code)

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

    First you have to add HTTParty gem to your Gemfile

    gem 'httparty'  # Makes http fun again (http client)
    

    我添加了此要点,其中包含步骤(6、7和8)这些是最有问题的步骤,几乎没有记录在任何地方.

    I've added this gist which contains the flow for step (6, 7 and 8) those are the most problematic steps and are not documented almost anywhere.

    要点出口的两种主要方法:

    the gist exports 2 main methods:

    Omniauth::Facebook.authenticate(authorization_code)
    

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

    which is used to authenticate the user with facebook and return the user_info, long_live_access_token (valid for 60 days)

    Omniauth::Facebook.deauthorize(access_token)
    

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

    which is used to de-authorize/revoke the access_token and application permissions on facebook...

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

    This is used for special requirement I have, when the user revoke the email permission requested on facebook login... we revoke the whole application permissions... this will prompt the user in the next login as if it's his first login ( no need to go to facebook apps and manually revoke the application)...

    这是控制器中的用法

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


    就这样...现在,如果您对实现的内部结构感兴趣...这是要点中显示的代码. (添加以供参考) 随意进行分叉,编辑,帮助使其变得更好.


    That's it... now if you are interested in the internals of the implementation... here is the code as seen in the gist. (added for reference) Feel free to fork it, edit it, help making it better.

    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
    

    这是另一个为instagram实现oauth的nodejs教程有助于我了解oauth2的工作方式(添加以供参考)

    here is another nodejs tutorial implementing oauth for instagram that helped me understand how oauth2 is working (added for reference)

    这篇关于使用omniauth和Facebook验证Rails API的用户身份?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆