En continuant depuis Future Social Authentication Improvements…
Nous sommes maintenant en train de migrer toutes les informations de « compte associé » dans une seule table de base de données. Cela aidera à réduire considérablement la duplication de la logique et permettra un développement plus rapide à 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
.
Cette publication n’est pas conçue comme un manuel d’instructions étape par étape pour ajouter un nouveau fournisseur d’authentification, mais elle vise à fournir un aperçu, en indiquant le code source pertinent si 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 plutôt étendre Auth::ManagedAuthenticator. Un exemple d’implémentation de base peut être trouvé dans l’authentificateur Facebook principal :
name, enabled? et register_middleware doivent être remplacés par les classes implémentant.
À part : pour la compatibilité multi-sites, 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 à ce sujet.
Toute la logique pour lier les comptes externes aux comptes Discourse est gérée par Auth::ManagedAuthenticator. Cela repose sur le fournisseur omniauth retournant des données dans le format défini dans leur documentation. Si une manipulation de ces données est nécessaire, les authentificateurs peuvent remplacer la méthode after_authenticate, et manipuler le jeton d’authentification 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 retournées par omniauth.
Une fois qu’une classe Authenticator a été définie, elle doit être enregistrée. Cela doit se produire tôt dans le cycle de vie de l’application, et ne peut pas se produire dans la méthode after_initialize d’un plugin. L’enregistrement minimum peut simplement contenir une référence à l’authentificateur. Dans un plugin, l’enregistrement peut être effectué en utilisant la fonction auth_provider. Par exemple :
auth_provider authenticator: OpenIDConnectAuthenticator.new()
Dans le cœur, l’enregistrement a lieu dans discourse.rb. Une liste complète des options AuthProvider possibles peut être trouvée ici. Le contenu textuel peut être défini en utilisant 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 en savoir plus sur ManagedAuthenticator. Fondamentalement, il comporte plusieurs opérations, options et contrôle la manière dont 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 que l’authentification OAuth2 est terminée. after_authenticate est appelé ici. can_connect_existing_user? est également utilisé ici.
Il existe des 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 créer votre propre implémentation.
UserAuthenticator est une classe de service qui aide à authentifier (vérifier la confirmation de l’e-mail ou le chemin OAuth2) les utilisateurs. after_create_account est appelé ici.
La logique principale reste à after_authenticate avec la classe de données Auth::Result. Nous suivons la structure des 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 essaiera de faire 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. Ceci est fait dans UsersController#create.
authentication = UserAuthenticator.new(user, session)
L’utilisateur est une nouvelle instance qui sera remplie par les données de session qui sont préparées par le fournisseur d’authentification. Croyez-moi, c’est juste de la magie.
Migration vers le nouveau système
Pour assurer une transition en douceur vers le nouveau système, les données doivent être migrées depuis l’ancien emplacement de stockage. Pour les fournisseurs d’authentification principaux, il peut s’agir de tables dédiées. Pour les plugins, 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 plugins d’authentification officiels. À ce stade, un exemple de migration plugin_store_row sera ajouté ici.
Ce document est contrôlé par version - suggérez des modifications sur github.