Arquitectura para fusionar múltiples cuentas de usuario juntas

176

Bien, tengo un sitio web donde puedes registrarte e iniciar sesión. También puede iniciar sesión con su cuenta de facebook, twitter o linkedin.

Es importante que los usuarios solo tengan una cuenta registrada. Entonces, de alguna manera, quiero fusionar las cuentas de los usuarios si usan diferentes métodos para iniciar sesión. ¿Cuál es la mejor solución para resolver esto?

Por ejemplo, el usuario inicia sesión con su cuenta de Facebook. Utilizo los datos para registrar una cuenta para él automáticamente. ¿Debo enviar un correo electrónico con un nombre de usuario y contraseña de nuestro sitio web? (Si esto está de acuerdo con la política de Facebook). ¿Debo darles una segunda pantalla donde puedan completar un nombre de usuario y contraseña? Pero esa no es la idea detrás de iniciar sesión con su cuenta de Facebook. Debería simplificar su procedimiento para participar.

También es posible que el usuario se haya registrado en nuestro sitio web y la próxima vez que inicie sesión con su cuenta de Twitter. ¿Cómo puedo fusionar estas 2 cuentas como una? Cual es la mejor manera?

Básicamente, mi pregunta es: tengo 4 formas diferentes en que un usuario se convierte en miembro de nuestro sitio web. ¿Cómo puedo asegurarme de que estas 4 formas solo creen una cuenta si un usuario decide usar varias formas? ¿Cuál es el mejor flujo para asegurarse de que no se convierta en una molestia para el propio usuario?


Editar:

3 años después de hacer esta pregunta, me estoy dando la respuesta en una serie de artículos: https://www.peternijssen.nl/social-network-authentication-setup/
https://www.peternijssen.nl/social- network-autenticación-google /
https://www.peternijssen.nl/social-network-authentication-merging-accounts/
https://www.peternijssen.nl/social-network-authentication-twitter-facebook/

PT
fuente
77
Por supuesto, es mejor tratar de evitar que un usuario tenga varias cuentas en primer lugar al permitir múltiples métodos de inicio de sesión como Stack Overflow, pero incluso SO tiene la capacidad de que los moderadores fusionen cuentas. Estoy ofreciendo recompensas para cualquiera que pueda describir una arquitectura para permitir esto. Tiene que haber una solución mejor que "actualizar post set UserID = 2 donde UserID = 1"
David Boike
el correo electrónico y el teléfono pueden usarse como clave de fusión, ¿otros?
Wuaner,
Hola, el enlace que has proporcionado no parece funcionar. Solo va a la página de inicio del sitio
vigamage
Actualizado los enlaces. Sin embargo, los artículos tienen 6 años.
PT

Respuestas:

120

Me enfrento exactamente a la misma tarea en este momento. El diseño que realicé es bastante simple, pero funciona bien.

La idea central es que los modelos para una identidad de sitio local y las identidades de sitio de terceros se mantienen aisladas, pero luego se vinculan. Por lo tanto, cada usuario que inicia sesión en el sitio tiene una identidad local que se asigna a cualquier número de identidades de sitios de terceros.

Un registro de identidad local contiene un mínimo de información, incluso podría ser un solo campo, solo una clave primaria. (Para mi aplicación, no me importa el correo electrónico, el nombre o la fecha de nacimiento del usuario; solo quiero saber si es la persona que ha estado iniciando sesión en esta cuenta todo el tiempo).

Las identidades de terceros contienen información relevante solo para la autenticación con un tercero. Para OAuth, esto generalmente significa un identificador de usuario (como una identificación, correo electrónico o nombre de usuario) y un identificador de servicio (que indica con qué sitio o servicio se autenticó). En otras partes de la aplicación, fuera de la base de datos, ese identificador de servicio se combina con un método para recuperar el identificador de usuario relevante de ese servicio, y así es como se realiza la autenticación. Para OpenID, empleamos el mismo enfoque, excepto que el método de autenticación es más generalizado (porque casi siempre podemos realizar exactamente el mismo protocolo, excepto que usamos una URL de identidad diferente, y ese es nuestro identificador de servicio).

Finalmente, mantengo un registro de las identidades de terceros que se emparejan con la identidad local. Para generar estos registros, el flujo se ve así:

  • Un usuario inicia sesión por primera vez con una identidad de terceros. Se crea un registro de identidad local, luego un registro de identidad de terceros y luego se emparejan.
  • En un panel de control, se le ofrece al usuario la oportunidad de vincular una cuenta iniciando sesión en servicios de terceros. (Bastante sencillo cómo funciona esto).
  • En el escenario en el que el usuario involuntariamente crea varias cuentas, la solución es bastante simple. Mientras el usuario inicia sesión en una de las cuentas, inicia sesión en otra que utilizó anteriormente para iniciar sesión en el sitio (a través de la función del panel de control anterior). El servicio web detecta esta colisión (que la identidad local del usuario conectado difiere de la identidad local que está vinculada a la identidad de un tercero que acaba de iniciar sesión) y se le solicita al usuario que combine la cuenta.

Fusionar cuentas es una cuestión de fusionar cada campo individual de la identidad local (que variará de una aplicación a otra, y debería ser fácil si solo tiene un par de campos en sus registros de identidad local), y luego garantizar las identidades de terceros vinculadas están vinculados a la identidad local resultante.

cheeken
fuente
1
¡Esta es una muy buena solución (me encanta la idea de detectar automáticamente la colisión de identidad local)! Me pregunto si encontraste una manera de iniciar sesión automáticamente al usuario en las cuentas "adicionales" que están vinculadas después del primer inicio de sesión en la aplicación. ¿El usuario tendría que iniciar sesión por separado en cada cuenta cada vez que visite (si no hay una sesión activa con estos proveedores)?
Alexandra
@Alexandra ¿Qué quieres decir con "cuentas adicionales"? ¿Se pregunta qué sucede cuando el usuario inicia sesión en la aplicación a través de varios autenticadores diferentes, creando una nueva identidad local con cada uno?
cheeken
Supongo que esto garantiza una aclaración adecuada y su propia pregunta: stackoverflow.com/questions/11060368/…
Alexandra
3
Pregunta, pero ¿qué pasa si el usuario se registra en el sitio usando la misma dirección de correo electrónico? ¿les avisamos que el correo electrónico ya existe (el correo electrónico que vino del modelo de un tercero) o aún los registramos en el sitio y luego fusionamos esas cuentas?
user962206
@ user962206 muchos servicios no le proporcionarán la dirección de correo electrónico 'real' de todos modos por razones de privacidad. Por ejemplo, Twitter no le dará ninguna dirección de correo electrónico, por lo que sé, Facebook le dará "[email protected]", que dudo que alguien use para registrarse.
kapex
44

Tiendo a encontrar muchos sitios fusionados basados ​​en el correo electrónico como factor de unión superpuesto.

Puedo ver que esta es una opción viable, pero nuevamente depende de su preferencia sobre cómo fusionarse. La dirección de correo electrónico es la forma principal en que las personas usan para verificar algunos cambios importantes de información en su sitio, como cambiar su contraseña, finalización del servicio, saldo de la cuenta, etc. . Culturalmente: creo que es razonable suponer que un correo electrónico es una identidad bastante única en todos los servicios de autenticación de OAuth. De acuerdo, es lo que piden los formularios de inicio de sesión para Facebook y Google.

Mi proceso de pensamiento actual.

La página de inicio de sesión tiene 3 opciones

  • La membresía de su propio sitio
  • Iniciar sesión con Facebook
  • Inicia sesión con google

1) El usuario inicia sesión por primera vez: desencadena un flujo de registro donde se crea y se completa una cuenta por primera vez.

 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) En otro momento, el usuario regresa pero decide hacer clic en 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) Ahora que se ha fusionado en la cuenta en la que confía, el correo electrónico en las entradas de su base de datos son los mismos en los que confía desde los inicios de sesión externos.

Entonces para inicios de sesión posteriores

Entonces, ¿qué sucede si primero tiene inicios de sesión externos y luego desea que un usuario pueda iniciar sesión con una contraseña más adelante?

Veo dos formas fáciles de hacer esto.

  • En cualquier primer inicio de sesión cuando se crea una cuenta desde una autenticación externa, solicite una contraseña para completar su primera entrada en su aplicación

  • Si ya se han registrado usando Facebook o Google primero, de alguna manera querían registrarse usando el formulario de registro de su propio sitio. Detecte si la dirección de correo electrónico que ingresaron ya existe, solicite una contraseña y envíeles un correo electrónico de confirmación una vez que se complete el registro.

Max Alexander
fuente
1
Cuando utiliza un esquema de autenticación externo (Facebook, Google, Twitter, etc.), nunca tendrá acceso a la contraseña del proveedor externo. La contraseña en el ejemplo anterior es la contraseña para su PROPIA aplicación web.
Max Alexander
66
Twitter no ofrece a los usuarios correo electrónico. Luego de su primera autenticación, si el ID de usuario de Twitter no existe, solicítele un correo electrónico y una contraseña. Si existe el correo electrónico y la contraseña, vincule las cuentas. Si no es así, almacene el correo electrónico y la contraseña para autenticaciones posteriores sin problemas. ¿Fue útil en absoluto?
Max Alexander
1
Como nota al margen, ahora es posible solicitar permisos para que su aplicación de Twitter obtenga la dirección de correo electrónico del usuario.
Sunil D.
2
¿Facebook hace que las personas verifiquen su correo electrónico? Sé que Github, por ejemplo, no. Un usuario malintencionado podría registrarse en Github con el nombre de correo electrónico de otra persona y luego obtener acceso a su cuenta en su sitio con esta estrategia. (La API de Github le dice si su correo electrónico está verificado o no; puede rechazar a cualquiera que se autentique con Github en una dirección de correo electrónico no verificada)
Matthew Moisen,
66
Esta es una violación de seguridad si un usuario se registra a través de las redes sociales, edita su dirección de correo electrónico en las redes sociales, otra persona toma la misma dirección de correo electrónico, se registra en las redes sociales y luego inicia sesión, se fusionarán con otra cuenta. Esto es muy poco probable, pero una violación no obstante. O me estoy perdiendo algo.
Shane
35

He pasado por esto con sled.com. Aquí hay múltiples problemas con respecto a la creación de cuentas y el soporte de múltiples cuentas de terceros para iniciar sesión. Algunos de ellos son:

  • ¿Necesita admitir tanto una contraseña local como inicios de sesión de terceros?

Para sled.com, he decidido eliminar la contraseña local debido al pequeño valor que agrega y el costo adicional de asegurar un formulario de ingreso de contraseña. Hay muchos ataques conocidos por romper contraseñas y si va a introducir contraseñas debe asegurarse de que no sean fáciles de romper. También debe almacenarlos en un hash unidireccional o similar para evitar que se filtren.

  • ¿Cuánta flexibilidad desea permitir para admitir múltiples cuentas de terceros?

Parece que ya eligió los tres proveedores de inicio de sesión: Facebook, Twitter y LinkedIn. Eso es genial porque significa que está utilizando OAuth y está trabajando con un conjunto bien definido de proveedores confiables. No soy fanático de OpenID. La pregunta restante es si necesita admitir varias cuentas de terceros del mismo proveedor (por ejemplo, una cuenta local con dos cuentas de Twitter vinculadas). Supongo que no, pero si lo hace, deberá acomodar eso en su modelo de datos.

Para Sled, admitimos el inicio de sesión con Facebook, Twitter y Yahoo! y dentro de cada cuenta de usuario, guarde una clave para cada una: {"_id": "djdjd99dj", "yahoo": "dj39djdj", twitter: "3723828732", "facebook": "12837287"}. Configuramos un montón de restricciones para garantizar que cada cuenta de terceros solo se pueda vincular a una sola cuenta local.

Si va a permitir varias cuentas del mismo proveedor externo, necesitará usar listas u otras estructuras para respaldar eso, y con eso, todas las otras restricciones para garantizar la unicidad.

  • ¿Cómo vincular varias cuentas?

La primera vez que el usuario se registra en su servicio, primero va al proveedor externo y regresa con una identificación de tercero verificada. Luego crea una cuenta local para ellos y recopila cualquier otra información que desee. Recopilamos su dirección de correo electrónico y también les pedimos que elijan un nombre de usuario local (intentamos rellenar previamente el formulario con su nombre de usuario existente del otro proveedor). Tener alguna forma de identificador local (correo electrónico, nombre de usuario) es muy importante para la recuperación de la cuenta más adelante.

El servidor sabe que este es un inicio de sesión por primera vez si el navegador no tiene una cookie de sesión (válida o caducada) para una cuenta existente, y que no se encuentra la cuenta de terceros utilizada. Intentamos informar al usuario que no solo están iniciando sesión, sino que están creando una nueva cuenta para que si ya tienen una cuenta, esperemos que pausen e inicien sesión con su cuenta existente.

Usamos exactamente el mismo flujo para vincular cuentas adicionales, pero cuando el usuario regresa de un tercero, la presencia de una cookie de sesión válida se utiliza para diferenciar entre un intento de vincular una nueva cuenta a una acción de inicio de sesión. Solo permitimos una cuenta de terceros de cada tipo y, si ya hay una vinculada, bloquea la acción. No debería ser un problema porque la interfaz para vincular una nueva cuenta está desactivada si ya tiene una (por proveedor), pero por las dudas.

  • ¿Cómo fusionar cuentas?

Si un usuario intentó vincular una nueva cuenta de terceros que ya está vinculada a una cuenta local, simplemente solicite que confirme que desea fusionar las dos cuentas (suponiendo que pueda manejar dicha fusión con su conjunto de datos, a menudo es más fácil decirlo). que hecho). También puede proporcionarles un botón especial para solicitar una fusión, pero en la práctica, todo lo que están haciendo es vincular otra cuenta.

Esta es una máquina de estado bastante simple. El usuario regresa del tercero con una identificación de cuenta de terceros. Su base de datos puede estar en uno de tres estados:

  1. La cuenta está vinculada a una cuenta local y no hay ninguna cookie de sesión presente -> Iniciar sesión
  2. La cuenta está vinculada a una cuenta local y hay una cookie de sesión presente -> Fusionar
  3. La cuenta no está vinculada a una cuenta local y no hay una cookie de sesión presente -> Registrarse
  4. La cuenta no está vinculada a una cuenta local y hay una cookie de sesión -> Vinculación de cuenta adicional

    • ¿Cómo realizar la recuperación de la cuenta con proveedores externos?

Esto sigue siendo territorio experimental. No he visto una experiencia de usuario perfecta para esto, ya que la mayoría de los servicios proporcionan una contraseña local junto a las cuentas de terceros y, por lo tanto, se centran en el caso de uso "Olvidé mi contraseña", no todo lo demás que puede salir mal.

Con Sled, hemos optado por utilizar "¿Necesita ayuda para iniciar sesión?" y cuando hace clic, solicite al usuario su correo electrónico o nombre de usuario. Lo buscamos y, si encontramos una cuenta coincidente, enviamos un correo electrónico a ese usuario con un enlace que puede iniciar sesión automáticamente en el servicio (válido por una vez). Una vez dentro, los llevamos directamente a la página de vinculación de cuentas, les decimos que deberían echar un vistazo y potencialmente vincular cuentas adicionales, y les mostramos las cuentas de terceros que ya han vinculado.

Eran Hammer
fuente
Esta solución es mucho mejor para mí, ¡Gracias!
Roy Shoa
2
La cookie de sesión no es lo suficientemente buena como para identificar al usuario. ¿Qué pasa si otro usuario usa el mismo dispositivo?
DeepBlue
23

Ambos enfoques para las cuentas de fusión automática dejan una vulnerabilidad bastante grande que permitiría a alguien hacerse cargo de una cuenta. Ambos parecen suponer que el usuario es quien dice ser cuando ofrece la opción de fusión a un usuario registrado.

Mi recomendación para mitigar la vulnerabilidad es solicitar que el usuario se autentique con uno de los proveedores de identidad conocidos antes de realizar la fusión para verificar la identidad del usuario.

Ejemplo: el usuario A se registra con identidad de Facebook. Algún tiempo después, vuelven a su sitio e intentan acceder con Windows Live ID e inician el proceso de registro. Su sitio le indicará al usuario A ... Parece que ya se ha registrado en Facebook anteriormente. Inicie sesión con Facebook (proporcione un enlace) y podemos combinar su Windows Live ID con su perfil existente.

Otra alternativa es almacenar un secreto compartido (contraseña / pregunta personal) en el registro inicial que el usuario debe proporcionar al fusionar identidades, sin embargo, esto lo lleva nuevamente al negocio de almacenar secretos compartidos. También significa que debe manejar el escenario en el que el usuario no recuerda el secreto compartido y el flujo de trabajo que lo acompaña.

Brad J
fuente
¿Qué haces si no recibes una dirección de correo electrónico del proveedor?
fred.kassi
1

La mayoría de las publicaciones son bastante antiguas y supongo que el servicio gratuito de autenticación Firebase de Google aún no existía. Después de verificar con OAuth, le pasa el token de OAuth y obtiene una identificación de usuario única que puede almacenar como referencia. Los proveedores admitidos son Google, Facebook, Twitter, GitHub y hay una opción para registrar proveedores personalizados y anónimos.

galki
fuente
Hay casos de uso en los que Firebase no tiene sentido. Por ejemplo, sistemas de intranet que tienen más de un inicio de sesión ..
Bostwick
-4

Debe permitir iniciar sesión desde una cuenta, luego, cuando inicie sesión, dé la opción de agregar otra cuenta diferente para fusionarse con ella.

Naftali aka Neal
fuente
44
¿Y qué sucede si el usuario no hace eso y se encuentra con 4 cuentas distintas? ¿Cómo se crea una arquitectura que permita una fusión en este caso?
David Boike
Dependiendo de sus necesidades, esto puede ser una sugerencia válida. Solo quiero advertir a aquellos que piensan que la fusión o vinculación de cuentas podría hacerse más tarde como algo posterior: si cree que esto es algo que podría desear más adelante, entonces querrá prepararse para eso al principio con el diseño de su base de datos: uno La opción es tener un UserGroup y un UserMapping. Puede asignar la identificación de usuario de OAuth o la identificación de usuario de correo electrónico y contraseña a un grupo de usuarios.
BumbleB2na