Go to Hackademy website

Intégrer les réseaux sociaux dans son application ruby on rails avec OAuth

Martin Catty

Posté par Martin Catty dans les catégories outils

Cet article est publié sous licence CC BY-NC-SA

Intégrer les réseaux sociaux dans son application ruby on rails avec omniauth

Dans mon introduction à OAuth, je vous avez laissé sur votre faim côté implémentation car ce n’était pas l’objet du billet.

J’avais juste brièvement évoqué omniauth comme l’outil indispensable.

Voyons donc aujourd’hui comment réellement intégrer cette solution avec devise.

Créer des applications sur les plateformes ciblées

Qu’elle que soit la plateforme en question (google, twitter, viadeo, facebook, linkedin…) vous aurez besoin de créer une application sur la plateforme cible. Par exemple sur twitter: https://dev.twitter.com/apps/new

Ce qui nous intéresse c’est de récupérer les clés qui nous permettront d’interagir avec l’application, à savoir le consumer key et le consumer secret.

Configurer notre application rails

En premier lieu, commençons par le plus simple, à savoir installer omniauth. Il suffit de l’ajouter dans le Gemfile.

gem 'omniauth'

Pour utiliser openid (pour s’authentifier via google par exemple), nous aurons besoin des gems suivantes:

gem 'oa-core'
gem 'oa-openid', :require => 'omniauth/openid'

Configurer devise

Omniauth s’intègre très bien avec devise, il suffit de configurer votre initializer devise.rb. Il est de bon ton d’avoir des applications pour votre environnement de dev et d’autres pour votre production.

if Rails.env.development?
  config.omniauth :twitter, 'CONSUMER_KEY', 'CONSUMER_SECRET'
  config.omniauth :facebook, 'CONSUMER_KEY', 'CONSUMER_SECRET', :scope => 'email'
  config.omniauth :linked_in, 'CONSUMER_KEY', 'CONSUMER_SECRET'
  config.omniauth :viadeo, 'CONSUMER_KEY', 'CONSUMER_SECRET'
  config.omniauth :google_apps, OpenID::Store::Filesystem.new('/tmp'), :domain => 'gmail.com'
else
  config.omniauth :twitter, 'CONSUMER_KEY', 'CONSUMER_SECRET'
  config.omniauth :facebook, 'CONSUMER_KEY', 'CONSUMER_SECRET', :scope => 'email'
  config.omniauth :linked_in, 'CONSUMER_KEY', 'CONSUMER_SECRET'
  config.omniauth :viadeo, 'CONSUMER_KEY', 'CONSUMER_SECRET'
  config.omniauth :google_apps, OpenID::Store::Filesystem.new('/tmp'), :domain => 'gmail.com'
end

Configurer notre modèle

Dans le modèle qui gère vos utilisateurs il faut rajouter omniauthable:

# user.rb
devise :omniauthable

Configurer nos routes et notre contrôleur

Nous allons indiquer à devise quel contrôleur utiliser lors de la réception des callbacks des différentes applications…

devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }

…et créer le contrôleur correspondant:

rails g controller users/omniauth_callbacks

Notre contrôleur doit hériter de Devise::OmniauthCallbacksController et implémenter une action par service supporté.

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def linked_in
    # some stuff
  end

  def twitter
  end
end

Dès lors que vous avez configuré un service, le formulaire de login de devise vous offre immédiatement un lien pour se connecter avec ce service.

Quand vous suivrez ce lien depuis votre application, la plateforme cible (ex: twitter) vous demandera d’autoriser explicitement l’utilisation de vos informations.

Si vous acceptez vous serez redirigé vers l’application que vous développez. A la redirection un hash (env[“omniauth.auth”]) est transmis. C’est là que vous trouverez toutes les informations de l’utilisateur selon la plateforme (email, nom, prénom…)

Gestion des autorisations

Beaucoup d’applications prennent la liberté de créer des comptes utilisateurs à la volée au retour de ces informations, en générant un mot de passe, voire un email, aléatoire.

Je pense personnellement que c’est une mauvaise idée. En faisant cela l’utilisateur ne comprendra pas qu’il vient de créer un compte sur votre application, donc il risque fort de créer 1 compte par plateforme utilisée.

De votre côté vous allez vous retrouver avec des données inconsistantes.

Créer un modèle authorization

Nous allons créer un modèle authorization qui permettra de stocker les informations propres à chaque service permettant de s’authentifier.

Cette autorisation est rattachée à un utilisateur, les champs indispensables sont donc:

rails g model Authorization user:references uid:string provider:string token:string secret:string
# user.rb
has_many :authorizations, :dependent => :destroy
# authorization.rb
belongs_to :user

Utilisateur connecté

Si vous êtes connecté, vous avez un current_user donc vous pouvez créer une authorization depuis votre contrôleur.

Depuis l’espace où vous êtes connecté dans votre application vous pouvez lister les autorisations présentes et permettre à l’utilisateur de les révoquer.

Utilisateur déconnecté

Si vous n’êtes pas connecté, la première chose à faire est d’essayer de voir si une autorisation correspondante à l’uid récupéré dans le hash existe depuis le contrôleur de callback.

Si c’est le cas on récupère l’user rattaché à cette autorisation et il devient à la fois authentifié et notre current_user.

S’il n’y a pas d’autorisation correspondante c’est certainement que l’utilisateur veut se créer un compte.

Dans ce cas on va simplement récupérer les informations, les utiliser pour construire notre utilisateur et afficher la vue d’inscription.

Restera alors uniquement à l’utilisateur de rentrer son mot de passe et son email si celui ci n’est pas fourni, ce qui est un confort non négligeable.

Problèmes rencontrés

L’intégration de google m’a posé quelques problèmes, lorsque j’étais authentifié et que je tentais d’autoriser google, au retour mon current_user était nil, la session avait été remise à 0.

En fouillant un peu je me suis rendu compte qu’un ticket avait été ouvert. Cela vient apparemment du formulaire d’envoi des paramètres à google qui ne contient pas le token de protection.

Ce token n’étant pas envoyé, rails fait un reset de la session.

Il y a deux solutions, surcharger le formulaire existant de omniauth pour google en utilisant le helper form_tag qui inclue tout seul le token, ou dans notre contrôleur de callback contourner la vérification:

protect_from_forgery :except => :google_apps

Documentation complémentaire

  • La doc de devise
  • Ce gist est un bon point de départ, mis à part qu’il crée des comptes à la volée, et que la quasi totalité du code privé du contrôleur devrait être déporté dans le modèle authorization.

L’équipe Synbioz.

Libres d’être ensemble.

Articles connexes

Linux Open : Ou comment automatiser des trucs simples

23/04/2020

Hey Reed ! Je viens de jouer à un super jeu. Tu connais ? https://www.youtube.com/watch?v=fWlHjpKmvh8 Je clique, ça s’ouvre sur mon navigateur web. Mhhh… Pourquoi mon environnement ne l’ouvre-t-il...

Facilitez-vous les tests avec Wiremock !

26/03/2020

Il arrive parfois que les applications que nous développons soient dépendantes d’autres applications ou API.

Les e-mails c'est bien, mangez-en !

13/02/2020

Les mails, c’est compliqué.

Una : pourquoi avoir créé notre propre ERP ?

13/01/2020

Una, qu’est-ce que c’est ? Una — prononcez [‘una] — est un progiciel de gestion intégré (PGI ou en anglais ERP pour « Enterprise Resource Planning ») développé par Synbioz pour ses propres besoins....