Je construis une API Rails et ai réussi à créer un moyen pour un utilisateur de s'authentifier à l'aide d'Omniauth Identity.
Nous publions simplement sur auth/identity/callback depuis le client, en lui passant un auth_key et un mot de passe.
Le serveur renvoie ensuite un jeton gardien qui utilise ensuite l'utilisateur pour accéder à l'application et s'identifier.
Ce diagramme illustre ceci:
Nous aimerions maintenant implémenter une connexion Facebook à partir du client, mais nous avons du mal à la faire fonctionner, à la fois théoriquement et concrètement.
Sur une application Rails simple avec Omniauth Identity, vous appelez simplement auth/facebook, mais si nous mettons un lien à partir de cela dans le client, le serveur est appelé et le serveur enregistre ensuite:
INFO -- omniauth: (facebook) Request phase initiated.
L'application est correctement configurée dans Facebook avec un identifiant et un secret. Vous pouvez donc peut-être renvoyer l'invite de connexion au serveur?
Je suis confus en enchaînant l'authentification. Toute aide appréciée avec reconnaissance!
la meilleure façon que j'ai trouvée (après avoir été bloqué pendant un moment sur cette question) est de faire votre omniauth2 (spécifiquement dans mon cas en utilisant satellizer plugin angulaire) manuellement ...
Je vais discuter de la solution pour Facebook, comme c'était mon cas, mais tout pourrait s'appliquer à n'importe quel autre fournisseur.
vous devez d’abord savoir comment fonctionne omniauth2 ( comme documenté pour les humains ici ) ...
code
(code d'autorisation)l'URL de redirection en arrière doit correspondre à l'URL de votre application frontale et non à l'URL du site principal; elle doit être spécifiée dans les configurations de votre application facebook
code
est renvoyé à la fenêtre parente qui a ouvert la fenêtre contextuelle.POST
à backend/auth/facebook
avec le paramètre code
.code
(Le code d'autorisation) est échangé contre access token
ici est décrit en détail comment échanger la code
contre un access-token
depuis documentation pour les développeurs facebook
Serveur: utilisez le access-token
récupéré à l'étape 6 pour récupérer les informations de l'utilisateur.
VOILA vous avez vous-même un utilisateur que vous pouvez fusionner/créer un compte/lien avec d'autres fournisseurs oauth/etc. mais gardez à l'esprit que l'utilisateur peut révoquer certaines autorisations (comme email, facebook prend en charge la révocation de certaines autorisations) ...
(assez parlé, montre-moi du code)
Vous devez d’abord ajouter HTTParty gem à votre Gemfile
gem 'httparty' # Makes http fun again (http client)
J'ai ajouté this Gist qui contient le déroulement de l'étape (6, 7 et 8). Ces étapes sont les plus problématiques et ne sont documentées presque nulle part.
gist exporte 2 méthodes principales:
Omniauth::Facebook.authenticate(authorization_code)
qui est utilisé pour authentifier l'utilisateur avec facebook et renvoyer le user_info, long_live_access_token (valable pendant 60 jours)
Omniauth::Facebook.deauthorize(access_token)
qui est utilisé pour désautoriser/révoquer les access_token et les autorisations d'application sur facebook ...
Ceci est utilisé pour l'exigence spéciale que j'ai, lorsque l'utilisateur révoque l'autorisation d'e-mail demandée sur la connexion facebook ... nous révoquons toutes les autorisations d'application ... ceci invitera l'utilisateur à la prochaine connexion, comme s'il s'agissait de sa première connexion (inutile pour accéder aux applications facebook et révoquer manuellement l'application) ...
voici comment il est utilisé dans le contrôleur
user_info, access_token = Omniauth::Facebook.authenticate(params['code'])
if user_info['email'].blank?
Omniauth::Facebook.deauthorize(access_token)
end
C'est ça ... maintenant si vous êtes intéressé par les aspects internes de la mise en oeuvre ... voici le code tel qu'il est vu dans le Gist. (ajouté pour référence) N'hésitez pas à le bifurquer, le modifier, aider à le rendre meilleur.
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
voici un autre tutoriel sur les nœuds implémentant oauth pour instagram qui m'a permis de comprendre le fonctionnement de oauth2 (ajouté pour référence)
Pour résoudre ce problème, la meilleure ressource que j'ai trouvée est l'application exemple Rails dans le dépôt satellite de github: https://github.com/sahat/satellizer/tree/master/examples/server/Ruby
Votre code de satellite appelle la méthode AuthController.authenticate . Cette méthode utilise les classes de modèle oauth pour chaque fournisseur pour convertir le code que vous recevez en un jeton d'accès. Ensuite, dans votre classe d'utilisateurs vous pouvez récupérer l'utilisateur qui correspond aux informations que vous avez obtenues du fournisseur.
A la fin, la méthode du contrôleur renvoie le jeton jwt au client.
Dans mon cas, la partie contrôleur est un peu différente, car j’utilise aussi le système d’authentification par mail/mot de passe, mais je copie les classes telles quelles et cela fonctionne à merveille.
Pour communiquer avec facebook api. Je recommande d'utiliser 'omniauth-facebook' gem . Vous pouvez cloner cet exemple pour en comprendre plus: https://github.com/ralphos/omniauth-facebook-example