Ответ 1
лучший способ, который я нашел (после того, как некоторое время застрял в этом вопросе), - это сделать свой omniauth2 (особенно в моем случае с использованием углового плагина спутника) вручную...
Я обсужу решение для Facebook, как это было в моем случае, но все может обратиться к любому другому провайдеру.
сначала вы должны знать, как работает omniauth2 (как описано для людей здесь)...
- Клиент: открыть всплывающее окно для аутентификации пользователя.
- Клиент: Войдите (при необходимости), затем авторизуйте приложение.
- Клиент: после успешного авторизации всплывающее окно перенаправляется обратно в ваше приложение. с
code
строки запроса (code
авторизации)
обратный URL-адрес обратной связи должен соответствовать вашему URL-адресу внешнего интерфейса, а не второму URL-адресу, и он должен быть указан в ваших конфигурациях приложений facebook
- Клиент: параметр
code
отправляется обратно в родительское окно, открывающее всплывающее окно. - Клиент. Окно родителя закрывает всплывающее окно и отправляет запрос
POST
дляbackend/auth/facebook
с параметромcode
. - Сервер:
code
(code
авторизации) обменивается наaccess token
здесь подробно описано, как обменивать code
для access-token
из документации разработчиков facebook
-
Сервер: используйте
access-token
полученный на шаге 6, чтобы получить информацию о пользователе. как описано здесь с красивыми наглядными пособиями. -
VOILA у вас есть пользователь, который вы можете объединить/создать учетную запись для /link с другими поставщиками oauth/etc. но в виду, что пользователь может отменить некоторые разрешения (например, электронная почта, facebook поддерживает отмену некоторых разрешений)...
(достаточно говорить, показать мне код)
Прежде всего, вы должны добавить HTTParty gem в свой Gemfile
gem 'httparty' # Makes http fun again (http client)
Я добавил этот gist, который содержит поток для шага (6, 7 и 8), которые являются наиболее проблематичными шагами и практически не документированы.
сущность экспорта 2 основных метода:
Omniauth::Facebook.authenticate(authorization_code)
который используется для аутентификации пользователя с помощью facebook и возврата user_info, long_live_access_token (действителен в течение 60 дней)
Omniauth::Facebook.deauthorize(access_token)
который используется для отмены авторизации/аннулирования прав доступа и прав приложения на facebook...
Это используется для специального требования, которое у меня есть, когда пользователь отменяет разрешение электронной почты, запрошенное для входа в 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
вот еще один учебник nodejs, реализующий oauth для instagram, который помог мне понять, как работает oauth2 (добавлено для справки)