我发现的最好的方法(在这个问题上被困了一段时间之后)是手动做你的omniauth2(特别是在我的情况下使用卫星角度插件)......
我将讨论 Facebook 的解决方案,就像我的情况一样,但一切都适用于任何其他提供商。
首先你必须知道omniauth2是如何工作的(正如这里为人类所记录的那样)......
- 客户端:打开一个弹出窗口供用户进行身份验证。
- 客户:登录(如有必要),然后授权应用程序。
- 客户端:授权成功后,弹窗将重定向回您的应用。带有
code
(授权码)查询字符串参数
重定向返回 url 必须与您的前端应用程序 url 而不是后端 url 匹配,并且必须在您的 facebook 应用程序配置中指定
- 客户端:将
code
参数发送回打开弹出窗口的父窗口。
- 客户端:父窗口关闭弹出窗口并向带有参数的
POST
请求发送。backend/auth/facebook
code
- 服务器:(
code
授权码)换取access token
这里详细描述了如何code
从access-token
facebook开发人员文档中交换
服务器:使用第6access-token
步中检索到的检索用户信息。
瞧,您已经拥有了一个用户,您可以合并/创建帐户/与其他 oauth 提供者/等链接。但请记住,用户可以撤销一些权限(如电子邮件,facebook 支持撤销一些权限)...
(说够了,给我看一些代码)
首先,您必须将 HTTParty gem 添加到您的 Gemfile
gem 'httparty' # Makes http fun again (http client)
我添加了这个要点,其中包含步骤(6、7 和 8)的流程,这些步骤是最有问题的步骤,几乎在任何地方都没有记录。
要点导出 2 个主要方法:
Omniauth::Facebook.authenticate(authorization_code)
用于通过 facebook 对用户进行身份验证并返回 user_info、long_live_access_token(有效期 60 天)
Omniauth::Facebook.deauthorize(access_token)
用于取消授权/撤销 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
就是这样......现在如果你对实现的内部感兴趣......这里是要点中看到的代码。(添加以供参考)随意分叉,编辑它,帮助它变得更好。
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 的工作原理(添加以供参考)