web-dev-qa-db-fra.com

Architecture pour fusionner plusieurs comptes d'utilisateurs ensemble

D'accord, j'ai un site Web où vous pouvez vous inscrire et vous connecter. Vous pouvez également vous connecter avec votre compte Facebook, Twitter ou linkedin.

Il est important que les utilisateurs n'aient qu'un seul compte enregistré. Donc, d'une manière ou d'une autre, je veux fusionner les comptes des utilisateurs s'ils utilisent différentes méthodes pour se connecter. Quelle est la meilleure solution pour résoudre ce problème?

Par exemple, l'utilisateur se connecte avec son compte Facebook. J'utilise les données pour lui ouvrir automatiquement un compte. Dois-je envoyer un e-mail avec un nom d'utilisateur et un mot de passe de notre site Web? (Si cela est d'accord avec la politique de Facebook). Dois-je leur donner un deuxième écran où ils peuvent saisir un nom d'utilisateur et un mot de passe? Mais ce n'est pas l'idée derrière la connexion avec votre compte Facebook. Cela devrait simplifier votre procédure de participation.

Il est également possible que l'utilisateur se soit enregistré sur notre site Web et la prochaine fois qu'il se connecte avec son compte Twitter. Comment puis-je fusionner ces 2 comptes en un seul? Quelle est la meilleure façon?

Donc, fondamentalement, ma question est la suivante: j'ai 4 façons différentes pour un utilisateur de devenir membre de notre site Web. Comment puis-je m'assurer que toutes ces 4 façons ne créent qu'un seul compte si un utilisateur décide d'utiliser plusieurs façons? Quel est le meilleur flux pour s'assurer qu'il ne devienne pas un problème pour l'utilisateur lui-même?


Modifier:

3 ans après avoir posé cette question, je donne moi-même la réponse dans une série d'articles: http://www.sitepoint.com/series/using-social-networks-as-a-login-system/

169
P.T.

Je suis actuellement confronté à la même tâche. Le design que j'ai élaboré est assez simple, mais il fonctionne bien.

L'idée centrale est que les modèles d'identité de site local et les identités de site tiers sont maintenus isolés, mais sont ensuite liés. Ainsi, chaque utilisateur qui se connecte au site a une identité locale qui correspond à un nombre quelconque d'identités de sites tiers.

Un enregistrement d'identité local contient un minimum d'informations - il peut même s'agir d'un seul champ - juste une clé primaire. (Pour mon application, je me fiche de l'adresse e-mail, du nom ou de la date de naissance de l'utilisateur - je veux juste savoir que c'est la personne qui s'est connectée à ce compte depuis le début.)

Les identités de tiers contiennent des informations pertinentes uniquement pour l'authentification auprès d'un tiers. Pour OAuth, cela signifie généralement un identifiant d'utilisateur (comme un identifiant, un e-mail ou un nom d'utilisateur) et un identifiant de service (indiquant avec quel site ou service a été authentifié). Dans d'autres parties de l'application, en dehors de la base de données, cet identifiant de service est associé à une méthode pour récupérer l'identifiant d'utilisateur pertinent de ce service, et c'est ainsi que l'authentification est effectuée. Pour OpenID, nous utilisons la même approche, sauf que la méthode d'authentification est plus généralisée (car nous pouvons presque toujours exécuter exactement le même protocole - sauf que nous utilisons une URL d'identité différente, et c'est notre identifiant de service).

Enfin, je garde une trace des identités tierces associées à quelle identité locale. Pour générer ces enregistrements, le flux ressemble à ceci:

  • Un utilisateur se connecte pour la première fois à l'aide d'une identité tierce. Un enregistrement d'identité local est créé, puis un enregistrement d'identité tiers, puis ils sont associés.
  • Dans un panneau de contrôle, l'utilisateur a la possibilité de lier un compte en se connectant à des services tiers. (Assez simple comment cela fonctionne.)
  • Dans le scénario où l'utilisateur crée involontairement plusieurs comptes, la solution est assez simple. Pendant que l'utilisateur est connecté sur l'un des comptes, il se connecte à un autre qu'il a précédemment utilisé pour se connecter au site (via la fonction du panneau de configuration ci-dessus). Le service Web détecte cette collision (que l'identité locale de l'utilisateur connecté diffère de l'identité locale liée à l'identité tierce qui vient de se connecter) et l'utilisateur est invité à fusionner le compte.

La fusion des comptes consiste à fusionner chaque champ individuel de l'identité locale (qui variera d'une application à l'autre, et devrait être facile si vous n'avez que quelques champs dans vos enregistrements d'identité locaux), puis à garantir les identités tierces liées sont liés à l'identité locale qui en résulte.

118
cheeken

J'ai tendance à trouver beaucoup de sites fusionnant sur la base de email comme facteur de jonction chevauchant.

Je peux voir que c'est une option viable, mais encore une fois cela dépend de votre préférence sur la façon de fusionner. L'adresse e-mail est le principal moyen utilisé par les gens pour vérifier certains changements d'informations importants sur votre site, tels que le changement de mot de passe, la résiliation du service, le solde du compte est faible, etc. . Culturellement: je pense qu'il est raisonnable de supposer qu'un e-mail est une identité assez unique parmi les services d'authentification OAuth. Certes, c'est ce que les formulaires de connexion pour Facebook et Google demandent.

Mon processus de pensée actuel.

La page de connexion a 3 options

  • L'adhésion de votre propre site
  • Se connecter avec Facebook
  • Connectez-vous avec google

1) Connexions utilisateur pour la première fois: déclenchez un flux d'enregistrement où un compte est créé et rempli pour la première fois.

 if the user logins using Facebook (or whatever 3rd party login)
      1) call the Facebook api asking for their information (email, name, etc...) 
      2) create an account membership entry in your database somewhat like this 

         Table = Users
         [ UserId   |       Email             | Password ]
         [    23     | "[email protected]" |  *null*  ]

      3) create an external auths entry like so
         *ProviderUserId is the unique id of that user on the provider's site

         Table = ExternalAuths
         [ ExternalAuthId  |  User_UserId   | ProviderName |   ProviderUserId  ]
         [    56           |      23        |   Facebook   |  "max.alexander.9"]

 if the user wants to create an account with your own registration it would just be this           

         Table = Users
         [ UserId   |       Email           |   Password  ]
         [    23     | [email protected] |  myCoolPwd  ]

2) À un autre moment, l'utilisateur revient mais décide de cliquer sur Google Login

      1) call the Google api asking for their information (email, name, etc...) 

      2) once you get the email, match it up to the userId entry with the existing email 

      3) create an additional External auth entry as such

         Table = ExternalAuths
         [ ExternalAuthId  |  User_UserId   | ProviderName |   ProviderUserId  ]
         [    56           |      23        |   Facebook   |  "max.alexander.9"]
         [    57           |      23        |    Google    |  "1234854368"     ]

3) Maintenant que vous avez fusionné sur le compte auquel vous faites confiance, les e-mails de vos entrées de base de données sont les mêmes que ceux auxquels vous faites confiance à partir des connexions externes.

Donc, pour les connexions suivantes

Que se passe-t-il si vous avez d'abord des connexions externes et que vous souhaitez ensuite qu'un utilisateur puisse se connecter avec un mot de passe plus tard?

Je vois deux façons simples de le faire

  • Lors de la première connexion lorsqu'un compte est créé à partir d'une authentification externe, demandez-leur un mot de passe pour terminer leur première entrée dans votre application

  • S'ils se sont déjà inscrits en utilisant Facebook ou Google d'abord, ils voulaient en quelque sorte s'inscrire en utilisant le formulaire d'inscription de votre propre site. Détectez si l'adresse e-mail qu'ils ont entrée existe déjà, demandez-leur un mot de passe et envoyez-leur une confirmation par e-mail une fois l'inscription terminée.

42
Max Alexander

J'ai vécu ça avec sled.com. Il y a plusieurs problèmes ici en ce qui concerne la création de comptes et la prise en charge de plusieurs comptes tiers pour la connexion. Certains d'entre eux sont:

  • Devez-vous prendre en charge à la fois un mot de passe local et des connexions tierces?

Pour sled.com, j'ai décidé de supprimer le mot de passe local en raison de la faible valeur ajoutée et du coût supplémentaire lié à la sécurisation d'un formulaire de saisie de mot de passe. Il existe de nombreuses attaques connues pour briser les mots de passe et si vous allez introduire des mots de passe, vous devez vous assurer qu'ils ne sont pas faciles à briser. Vous devez également les stocker dans un hachage unidirectionnel ou quelque chose de similaire pour éviter les fuites.

  • Quelle flexibilité souhaitez-vous accorder à la prise en charge de plusieurs comptes tiers?

Il semble que vous ayez déjà choisi les trois fournisseurs de connexion: Facebook, Twitter et LinkedIn. C'est génial car cela signifie que vous utilisez OAuth et que vous travaillez avec un ensemble bien défini de fournisseurs de confiance. Je ne suis pas fan d'OpenID. La question qui reste est de savoir si vous devez prendre en charge plusieurs tiers- comptes de partie du même fournisseur (par exemple, un compte local avec deux comptes Twitter liés). Je suppose que non, mais si vous le faites, vous devrez tenir compte de cela dans votre modèle de données.

Pour Sled, nous prenons en charge la connexion avec Facebook, Twitter et Yahoo! et dans chaque compte d'utilisateur, stockez une clé pour chacun: {"_id": "djdjd99dj", "yahoo": "dj39djdj", Twitter: "3723828732", "facebook": "12837287"}. Nous avons configuré un ensemble de contraintes pour garantir que chaque compte tiers ne peut être lié qu'à un seul compte local.

Si vous allez autoriser plusieurs comptes du même fournisseur tiers, vous devrez utiliser des listes ou d'autres structures pour prendre en charge cela, et avec cela, toutes les autres restrictions pour garantir l'unicité.

  • Comment lier plusieurs comptes?

La première fois que l'utilisateur s'inscrit à votre service, il va d'abord chez le fournisseur tiers et revient avec un identifiant tiers vérifié. Vous créez ensuite un compte local pour eux et collectez toutes les autres informations que vous souhaitez. Nous recueillons leur adresse e-mail et leur demandons également de choisir un nom d'utilisateur local (nous essayons de préremplir le formulaire avec leur nom d'utilisateur existant de l'autre fournisseur). Avoir une certaine forme d'identifiant local (email, nom d'utilisateur) est très important pour la récupération de compte plus tard.

Le serveur sait qu'il s'agit d'une première connexion si le navigateur n'a pas de cookie de session (valide ou expiré) pour un compte existant et que le compte tiers utilisé est introuvable. Nous essayons d'informer l'utilisateur qu'il ne se connecte pas seulement, mais qu'il crée un nouveau compte afin que s'il a déjà un compte, il espère qu'il fasse une pause et se connecte avec son compte existant à la place.

Nous utilisons exactement le même flux pour lier des comptes supplémentaires, mais lorsque l'utilisateur revient du tiers, la présence d'un cookie de session valide est utilisée pour différencier une tentative de lier un nouveau compte à une action de connexion. Nous n'autorisons qu'un seul compte tiers de chaque type et s'il y en a déjà un, bloquons l'action. Cela ne devrait pas être un problème car l'interface pour lier un nouveau compte est désactivée si vous en avez déjà un (par fournisseur), mais juste au cas où.

  • Comment fusionner des comptes?

Si un utilisateur a tenté de lier un nouveau compte tiers qui est déjà lié à un compte local, vous lui demandez simplement de confirmer qu'il souhaite fusionner les deux comptes (en supposant que vous pouvez gérer une telle fusion avec votre ensemble de données - souvent plus facile à dire). que fait). Vous pouvez également leur fournir un bouton spécial pour demander une fusion, mais en pratique, tout ce qu'ils font est de lier un autre compte.

Il s'agit d'une machine d'état assez simple. L'utilisateur revient du tiers avec un identifiant de compte tiers. Votre base de données peut être dans l'un des trois états suivants:

  1. Le compte est lié à un compte local et aucun cookie de session n'est présent -> Connexion
  2. Le compte est lié à un compte local et un cookie de session est présent -> Fusionner
  3. Le compte n'est pas lié à un compte local et aucun cookie de session n'est présent -> Inscription
  4. Le compte n'est pas lié à un compte local et un cookie de session est présent -> Lier un compte supplémentaire

    • Comment effectuer la récupération de compte avec des fournisseurs tiers?

C'est encore un territoire expérimental. Je n'ai pas vu une UX parfaite pour cela car la plupart des services fournissent à la fois un mot de passe local à côté des comptes tiers et se concentrent donc sur le cas d'utilisation "oublié mon mot de passe", pas tout le reste qui peut mal tourner.

Avec Sled, nous avons choisi d'utiliser "Besoin d'aide pour vous connecter?" et lorsque vous cliquez, demandez à l'utilisateur son e-mail ou son nom d'utilisateur. Nous le recherchons et si nous trouvons un compte correspondant, envoyez à cet utilisateur un lien qui peut automatiquement le connecter au service (valable une fois). Une fois entrés, nous les amenons directement sur la page de liaison de compte, leur disons qu'ils devraient jeter un œil et éventuellement lier des comptes supplémentaires, et leur montrer les comptes tiers qu'ils ont déjà liés.

34
Eran Hammer

Les deux approches pour la fusion automatique des comptes laissent une assez grande vulnérabilité qui permettrait à quelqu'un de reprendre un compte. Ils semblent tous deux faire l'hypothèse que l'utilisateur est ce qu'ils disent être lorsqu'ils offrent l'option de fusion à un utilisateur qui s'enregistre.

Ma recommandation pour atténuer la vulnérabilité est de demander à l'utilisateur de s'authentifier auprès de l'un des fournisseurs d'identité connus avant d'effectuer la fusion pour vérifier l'identité de l'utilisateur.

Exemple: l'utilisateur A s'enregistre avec l'identité Facebook. Un peu plus tard, ils reviennent sur votre site et tentent d'accéder avec Windows Live ID et de démarrer le processus d'inscription. Votre site invitera l'utilisateur A avec ... Il semble que vous vous soyez déjà inscrit sur Facebook. Veuillez vous connecter avec Facebook (fournir un lien) et nous pouvons fusionner votre Windows Live ID avec votre profil existant.

Une autre alternative consiste à stocker un secret partagé (mot de passe/question personnelle) lors de l'inscription initiale que l'utilisateur doit fournir lors de la fusion des identités, mais cela vous ramène à l'entreprise de stockage de secrets partagés. Cela signifie également que vous devez gérer le scénario où l'utilisateur ne se souvient pas du secret partagé et du flux de travail qui l'accompagne.

21
Brad J

La plupart des messages sont assez anciens et je suppose que le service gratuit Authentification Firebase de Google n'était pas encore là. Après avoir vérifié avec OAuth, vous lui passez le jeton OAuth et obtenez un identifiant utilisateur unique que vous pouvez stocker pour référence. Les fournisseurs pris en charge sont Google, Facebook, Twitter, GitHub et il existe une option pour enregistrer des fournisseurs personnalisés et anonymes.

2
galki

Excellentes réponses et ressources ci-dessus. Ma contribution est résumée ici ... https://github.com/JavascriptMick/learntree.org/blob/master/design/Schema.md

TLDR: schémas de compte et de personne séparés. 2 variantes de compte, e-mail et OAuth.

Compte-authentifie-> Personne

0
Michael Dausmann