Suite de Future Social Authentication Improvements…
Nous sommes actuellement en train de regrouper toutes les informations relatives aux « comptes associés » dans une unique table de base de données. Cela permettra de réduire considérablement la logique dupliquée et de faciliter le développement à l’avenir. Par exemple, la migration de notre logique Twitter principale vers le nouveau système a réduit le nombre de lignes de code de 136 à seulement 24
.
Ce message n’est pas conçu pour être un mode d’emploi étape par étape pour ajouter un nouveau fournisseur d’authentification, mais il vise à fournir un aperçu général, en pointant vers le code source pertinent lorsque nécessaire.
Implémentation d’un authentificateur
Chaque authentificateur doit implémenter une sous-classe de Auth::Authenticator. Pour utiliser la nouvelle logique partagée, l’authentificateur peut à la place étendre Auth::ManagedAuthenticator. Un exemple d’implémentation minimale peut être trouvé dans l’authentificateur Facebook principal :
name, enabled? et register_middleware doivent être redéfinis par les classes implémentant l’authentificateur.
Note : pour la compatibilité multisite, il est important que toute information spécifique au site soit fournie à omniauth dans une lambda
setup, plutôt que d’être fixée au moment de la définition. Voir tous les authentificateurs principaux pour des exemples de ceci.
Toute la logique de liaison des comptes externes aux comptes Discourse est gérée par Auth::ManagedAuthenticator. Cela repose sur le fournisseur omniauth renvoyant les données dans le format défini dans leur documentation. Si toute manipulation de ces données est nécessaire, les authentificateurs peuvent redéfinir la méthode after_authenticate et manipuler le auth_token comme requis. Par exemple, l’authentificateur Twitter principal supprime toutes les informations extra du jeton :
Les données sont stockées dans la table de base de données user_associated_accounts. provider_uid, info, credentials et extra sont tous pris directement des données renvoyées par omniauth.
Une fois qu’une classe Authenticator a été définie, elle doit être enregistrée. Cela doit se faire tôt dans le cycle de vie de l’application, et ne peut pas se produire dans la méthode after_initialize d’une extension. L’enregistrement minimal peut simplement contenir une référence à l’authentificateur. Dans une extension, l’enregistrement peut être effectué en utilisant la fonction auth_provider. Par exemple :
auth_provider authenticator: OpenIDConnectAuthenticator.new()
Dans le code principal, l’enregistrement a lieu dans discourse.rb. Une liste complète des options possibles de AuthProvider peut être trouvée ici. Le contenu texte peut être défini à l’aide de ces options, mais il est préférable de fournir des chaînes localisables dans client.en.yml en suivant les clés standard. Par exemple :
Notes supplémentaires sur ManagedAuthenticator par @fantasticfears
ManagedAuthenticator en détail
Vous pourriez avoir besoin de travailler sur quelque chose de spécial pour l’authentification. Et vous aimeriez peut-être en savoir plus sur ManagedAuthenticator. En gros, il possède plusieurs opérations, options, et contrôle comment les données seront utilisées.
Discourse gère les informations utilisateur avec deux contrôleurs. Users::OmniauthCallbacksController gère la charge utile une fois l’authentification OAuth2 terminée. after_authenticate est appelé ici. can_connect_existing_user? est également utilisé ici.
Il y a quelques méthodes privées que vous pouvez lire pour comprendre comment fonctionnent les différents champs de données.
if authenticator.can_connect_existing_user? && current_user
@auth_result = authenticator.after_authenticate(auth, existing_account: current_user)
else
@auth_result = authenticator.after_authenticate(auth)
end
UsersController a revoke_account qui utilise can_revoke? et revoke. Mais pour que la méthode revoke fonctionne à distance, vous devez construire votre propre implémentation.
UserAuthenticator est une classe de service aidant à l’authentification (vérification de la confirmation d’e-mail ou du chemin OAuth2) des utilisateurs. after_create_account est appelé ici.
La logique principale reste dans after_authenticate avec la classe de données Auth::Result. Nous suivons la structure de données ici. extra_data sera passé à after_create_account pour créer les enregistrements associés.
result.extra_data = {
provider: auth_token[:provider],
uid: auth_token[:uid],
info: auth_token[:info],
extra: auth_token[:extra],
credentials: auth_token[:credentials]
}
Il tentera de correspondre et de se connecter à un compte existant.
Vous vous demandez peut-être pourquoi la création automatique de compte est possible mais qu’il n’y a pas de User.create. Cela se fait dans UsersController#create.
authentication = UserAuthenticator.new(user, session)
L’utilisateur est une nouvelle instance qui sera remplie par les données de session préparées par le fournisseur d’authentification. Faites-moi confiance, c’est de la magie pure.
Migration vers le nouveau système
Pour fournir une bascule transparente vers le nouveau système, les données doivent être migrées depuis l’emplacement de stockage ancien. Pour les fournisseurs d’authentification principaux, il peut s’agir de tables dédiées. Pour les extensions, il peut s’agir de plugin_store_rows ou de oauth2_user_infos. Les données minimales requises dans une ligne user_associated_accounts sont provider_name, provider_uid et user_id. Pour un exemple de migration, voir :
Une fois que le système ManagedAuthenticator aura été publié sur la branche stable avec la v2.2.0, nous commencerons à migrer les extensions d’authentification officielles. À ce stade, un exemple de migration de plugin_store_row sera ajouté ici.
Ce document est sous contrôle de version - suggérez des modifications sur github.