Архитектура для объединения нескольких учетных записей пользователей - PullRequest
169 голосов
/ 12 июля 2011

Хорошо, у меня есть сайт, где вы можете зарегистрироваться и войти.Вы также можете войти в систему с помощью учетной записи Facebook, Twitter или linkedin.

Важно, чтобы у пользователей была зарегистрирована только одна учетная запись.Так или иначе, я хочу объединить учетные записи пользователей, если они используют разные методы для входа в систему.Как лучше всего решить эту проблему?

Например, пользователь входит в свою учетную запись Facebook.Я использую данные для автоматической регистрации аккаунта для него.Должен ли я отправить электронное письмо с именем пользователя и паролем нашего сайта?(Если это нормально с политикой Facebook).Должен ли я дать им второй экран, где они могут ввести имя пользователя и пароль?Но это не идея входа с вашей учетной записью Facebook.Это должно упростить вашу процедуру участия.

Также возможно, что пользователь зарегистрировался на нашем сайте и в следующий раз он войдет в систему со своей учетной записью Twitter.Как я могу объединить эти 2 аккаунта в один?Какой самый лучший способ?

Итак, в основном мой вопрос: у меня есть 4 различных способа, которыми пользователь становится участником нашего сайта.Как я могу убедиться, что все эти 4 способа создают только одну учетную запись, если пользователь решает использовать несколько способов?Как лучше всего убедиться, что это не станет проблемой для самого пользователя?


Редактировать:

Через 3 года после того, как я задал этот вопрос, я даю ответя в серии статей: http://www.sitepoint.com/series/using-social-networks-as-a-login-system/

Ответы [ 7 ]

117 голосов
/ 02 августа 2011

В данный момент я сталкиваюсь с точно такой же задачей. Разработанный мною дизайн довольно прост, но работает хорошо.

Основная идея заключается в том, что модели для идентичности локального сайта и стороннего идентификатора сайта остаются изолированными, но позднее связываются. Таким образом, у каждого пользователя, который входит на сайт, есть локальный идентификатор, который сопоставляется с любым количеством сторонних идентификаторов сайта.

Локальная идентификационная запись содержит минимум информации - это может быть даже одно поле - только первичный ключ. (Для моего приложения меня не волнует электронная почта, имя или дата рождения пользователя - я просто хочу знать, что это человек, который все время заходил в эту учетную запись.)

Сторонние идентификационные данные содержат информацию, относящуюся только к аутентификации третьей стороны. Для OAuth это, как правило, означает идентификатор пользователя (например, идентификатор, адрес электронной почты или имя пользователя) и идентификатор службы (указывающий, с каким сайтом или службой был аутентифицирован). В других частях приложения, за пределами базы данных, этот идентификатор службы связан со способом извлечения соответствующего идентификатора пользователя из этой службы, и именно так выполняется аутентификация. Для OpenID мы используем тот же подход, за исключением того, что метод аутентификации является более обобщенным (потому что мы почти всегда можем выполнять точно такой же протокол - за исключением того, что мы используем другой идентификационный URL, и это наш идентификатор сервиса).

Наконец, я веду записи о том, какие сторонние удостоверения связаны с каким локальным удостоверением. Для генерации этих записей поток выглядит следующим образом:

  • Пользователь впервые входит в систему, используя стороннюю идентификационную информацию. Создается локальная идентификационная запись, затем сторонняя идентификационная запись, а затем они связываются.
  • В панели управления пользователю предлагается возможность связать аккаунт, войдя в сторонние сервисы. (Довольно просто, как это работает.)
  • В случае, когда пользователь невольно создает несколько учетных записей, решение довольно простое. Когда пользователь входит в одну из учетных записей, он входит в другую, которую он ранее использовал для входа на сайт (с помощью функции панели управления выше). Веб-служба обнаруживает эту коллизию (локальная идентификация вошедшего в систему пользователя отличается от локальной идентификации, которая связана со сторонней идентификацией, которая только что вошла в систему), и пользователю предлагается объединить учетную запись.

Объединение учетных записей - это вопрос объединения каждого отдельного поля локальной идентичности (которое будет варьироваться от приложения к приложению и должно быть простым, если у вас есть только несколько полей в ваших локальных записях идентичности), а затем обеспечение связанной третьей идентичности сторон связаны с результирующей локальной идентичностью.

42 голосов
/ 26 января 2013

Я склонен считать, что многие сайты объединяются на основе email как перекрывающегося фактора объединения.

Я вижу, что это приемлемый вариант, но опять же, это зависит от ваших предпочтений относительно того, как объединить. Адрес электронной почты - это основной способ, с помощью которого люди проверяют изменения важной информации на вашем сайте, такие как изменение пароля, прекращение обслуживания, низкий уровень остатка на счете и т. Д. Это почти похоже на систему нумерации социальных сетей в Интернете, но с возможностью связи. , С культурной точки зрения: я думаю, что разумно предположить, что электронная почта является довольно уникальной личностью в службах аутентификации OAuth. Конечно, это то, что запрашивают формы входа в Facebook и Google.

Мой текущий мыслительный процесс.

Страница входа имеет 3 варианта

  • Членство в вашем собственном сайте
  • Войти через Facebook
  • Войти через Google

1) Пользователь впервые входит в систему: запустить поток регистрации, в котором учетная запись создается и заполняется впервые.

 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     | "newuser@coolmail.com" |  *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     | newuser@coolmail.com |  myCoolPwd  ]

2) В другое время пользователь возвращается, но решает нажать на логин Google

      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) Теперь вы вошли в учетную запись, которой вы доверяете, и сообщения электронной почты в вашей базе данных совпадают с теми, которым вы доверяете из внешних входов в систему.

Так что для последующих логинов

Так что, если у вас сначала есть внешние логины, а затем вы хотите, чтобы пользователь мог позже войти в систему с паролем?

Я вижу два простых способа сделать это

  • При любом первом входе в систему, когда учетная запись создается из внешней аутентификации, попросите у них пароль для завершения их первого входа в ваше приложение

  • Если они уже зарегистрировались, используя Facebook или Google, то почему-то хотели зарегистрироваться, используя регистрационную форму вашего собственного сайта. Определите, существует ли уже введенный адрес электронной почты, попросите пароль и отправьте подтверждение по электронной почте после завершения регистрации.

34 голосов
/ 02 августа 2011

Я прошел через это с sled.com. Здесь возникает множество проблем, связанных с созданием учетных записей и поддержкой нескольких сторонних учетных записей для входа в систему. Некоторые из них:

  • Нужно ли поддерживать как локальный пароль, так и сторонние логины?

Для sled.com я решил отказаться от локального пароля из-за небольшого значения, которое он добавляет, и дополнительных затрат на защиту формы ввода пароля. Существует много известных атак для взлома паролей, и если вы собираетесь вводить пароли, вы должны убедиться, что их нелегко взломать. Вам также нужно хранить их в одностороннем хеше или в чем-то подобном, чтобы предотвратить утечку.

  • Насколько гибко вы хотите поддерживать несколько сторонних учетных записей?

Похоже, вы уже выбрали трех провайдеров входа в систему: Facebook, Twitter и LinkedIn. Это здорово, потому что это означает, что вы используете OAuth и работаете с четко определенным набором доверенных поставщиков. Я не фанат OpenID. Остается вопрос, нужно ли вам поддерживать несколько сторонних учетных записей от одного и того же провайдера (например, одну локальную учетную запись с двумя связанными учетными записями Twitter). Я предполагаю, что нет, но если вы это сделаете, вам нужно будет учесть это в вашей модели данных.

Для Sled мы поддерживаем вход через Facebook, Twitter и Yahoo! и в каждой учетной записи пользователя сохраните ключ для каждого из них: {"_id": "djdjd99dj", "yahoo": "dj39djdj", twitter: "3723828732", "facebook": "12837287"}. Мы установили несколько ограничений, чтобы гарантировать, что каждая сторонняя учетная запись может быть связана только с одной локальной учетной записью.

Если вы собираетесь разрешить несколько учетных записей от одного и того же стороннего поставщика, вам необходимо использовать списки или другие структуры для поддержки этого, а вместе с этим и все другие ограничения для обеспечения уникальности.

  • Как связать несколько аккаунтов?

Когда пользователь впервые регистрируется в вашей службе, он сначала обращается к стороннему поставщику и возвращается с проверенным сторонним идентификатором. Затем вы создаете для них локальную учетную запись и собираете любую другую информацию, которую хотите. Мы собираем их адрес электронной почты, а также просим их выбрать локальное имя пользователя (мы пытаемся предварительно заполнить форму их существующим именем пользователя от другого поставщика). Наличие некоторой формы локального идентификатора (адрес электронной почты, имя пользователя) очень важно для последующего восстановления учетной записи.

Сервер знает, что это первый вход в систему, если в браузере нет файла cookie сеанса (действительного или просроченного) для существующей учетной записи, а используемая сторонняя учетная запись не найдена. Мы пытаемся проинформировать пользователя, что он не просто выполняет вход, но и создает новую учетную запись, чтобы, если у него уже была учетная запись, вместо этого он, возможно, приостановился и вошел в систему со своей существующей учетной записью.

Мы используем точно такой же поток для связывания дополнительных учетных записей, но когда пользователь возвращается от третьей стороны, наличие действительного файла cookie сеанса используется для разграничения между попыткой связать новую учетную запись с действием входа в систему. Мы разрешаем только одну стороннюю учетную запись каждого типа и, если она уже существует, блокируем действие. Это не должно быть проблемой, потому что интерфейс для связи с новой учетной записью отключен, если у вас уже есть одна (на одного провайдера), но на всякий случай.

  • Как объединить аккаунты?

Если пользователь попытался связать новую стороннюю учетную запись, которая уже связана с локальной учетной записью, вы просто предлагаете ему подтвердить, что он хочет объединить две учетные записи (при условии, что вы можете обработать такое слияние с вашим набором данных - часто легче сказать, чем сделать). Вы также можете предоставить им специальную кнопку для запроса слияния, но на практике все, что они делают - это связывают другую учетную запись.

Это довольно простой конечный автомат. Пользователь возвращается со сторонней стороны с идентификатором сторонней учетной записи. Ваша база данных может находиться в одном из трех состояний:

  1. Учетная запись связана с локальной учетной записью, а сессионный файл cookie неприсутствует -> Логин
  2. Учетная запись связана с локальной учетной записью, и файл cookie сеанса присутствует -> Объединить
  3. Учетная запись не связана с локальной учетной записью, и отсутствует файл cookie сеанса-> Регистрация
  4. Учетная запись не связана с локальной учетной записью, и имеется файл cookie сеанса -> Связывание дополнительной учетной записи

    • Как выполнить восстановление учетной записи с помощью третьейсторонние поставщики?

Это все еще экспериментальная территория.Я не видел идеального UX для этого, так как большинство служб предоставляют локальный пароль рядом со сторонними учетными записями и, следовательно, фокусируются на сценарии использования «забыл мой пароль», а не на всем остальном, что может пойти не так.

С Sled мы решили использовать «Нужна помощь при входе?»и когда вы нажимаете, спросите пользователя его адрес электронной почты или имя пользователя.Мы ищем его и, если найдем подходящую учетную запись, отправим пользователю по электронной почте ссылку, по которой он может автоматически войти в службу (на один раз).Оказавшись здесь, мы перенаправляем их прямо на страницу привязки учетных записей, говорим им, что они должны взглянуть и потенциально связывать дополнительные учетные записи, и показываем им сторонние учетные записи, с которыми они уже связались.

21 голосов
/ 25 ноября 2012

Оба подхода к автоматическому слиянию учетных записей оставляют довольно большую уязвимость, которая позволит кому-либо завладеть учетной записью.Похоже, они оба предполагают, что пользователь является тем, кем они себя называют, когда они предлагают опцию слияния регистрируемому пользователю.

Моя рекомендация по снижению уязвимости состоит в том, чтобы запросить у пользователя аутентификацию на одном из известныхПоставщики удостоверений перед выполнением слияния для проверки личности пользователя.

Пример: пользователь A регистрируется с удостоверением Facebook.Через некоторое время они возвращаются на ваш сайт и пытаются получить доступ с помощью идентификатора Windows Live ID и начинают процесс регистрации.Ваш сайт предложит пользователю A с ... Похоже, что вы зарегистрировались в Facebook ранее.Пожалуйста, войдите с помощью Facebook (укажите ссылку), и мы сможем объединить ваш идентификатор Windows Live ID с существующим профилем.

Другой вариант - сохранить общий секретный пароль (пароль / личный вопрос) при первоначальной регистрации, которую должен предоставить пользователь.однако при объединении идентификаторов вы возвращаетесь к делу хранения общих секретов.Это также означает, что вам придется работать со сценарием, в котором пользователь не запоминает общий секрет, и рабочим процессом, который сопровождает его.

2 голосов
/ 16 августа 2016

Большинство постов довольно старые, и я думаю, что бесплатной службы Google Firebase Authentication еще не было. После проверки с помощью OAuth вы передаете ему токен OAuth и получаете уникальный идентификатор пользователя, который вы можете сохранить для справки. Поддерживаемые провайдеры: Google, Facebook, Twitter, GitHub, есть возможность зарегистрировать нестандартных и анонимных провайдеров.

0 голосов
/ 15 июня 2018

Отличные ответы и ресурсы выше.Мой вклад обобщен здесь ... https://github.com/JavascriptMick/learntree.org/blob/master/design/Schema.md

TLDR: отдельные схемы Account и Person.2 варианта учетной записи, электронной почты и OAuth.

Аккаунт-аутентификация-> Персона

0 голосов
/ 12 июля 2011

Вы должны разрешить вход в систему с одной учетной записи, затем при входе в систему можно добавить другую учетную запись для объединения с ней.

...