Архитектура для объединения нескольких учетных записей пользователей

176

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

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

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

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

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


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

Спустя 3 года после того, как я задал этот вопрос, я даю ответ сам в серии статей: https://www.peternijssen.nl/social-network-authentication-setup/
https://www.peternijssen.nl/social- network-authentication-google /
https://www.peternijssen.nl/social-network-authentication-merging-accounts/
https://www.peternijssen.nl/social-network-authentication-twitter-facebook/

PT
источник
7
Конечно, лучше всего сначала попытаться запретить пользователю иметь несколько учетных записей, разрешив несколько методов входа в систему, таких как переполнение стека, но даже у SO есть возможность для модераторов объединять учетные записи. Я предлагаю щедрость для тех, кто может описать архитектуру, позволяющую это сделать. Должно быть лучшее решение, чем «обновить набор сообщений UserID = 2, где UserID = 1»
Дэвид Бойк
электронная почта и телефон могут использоваться в качестве ключа слияния, любые другие?
Wuaner
Здравствуйте, ссылка, которую вы предоставили, похоже, не работает. Идет только на главную страницу сайта
vigamage
Обновлены ссылки. Статьям уже 6 лет.
PT

Ответы:

120

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

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

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

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

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

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

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

cheeken
источник
1
Это очень хорошее решение (мне нравится идея автоматического определения локального столкновения идентичности)! Мне интересно, если вы нашли способ автоматического входа пользователя в «дополнительные» учетные записи, которые связаны после первого входа в приложение. Должен ли пользователь входить в каждую учетную запись отдельно при каждом посещении (если с этими провайдерами уже нет активного сеанса)?
Александра
@Alexandra Что вы подразумеваете под "дополнительными аккаунтами"? Вы спрашиваете, что происходит, когда пользователь входит в приложение через несколько разных аутентификаторов, создавая новую локальную идентификацию с каждым?
cheeken
Я предполагаю, что это требует надлежащего разъяснения и своего собственного вопроса: stackoverflow.com/questions/11060368/…
Александра
3
Вопрос, однако, но что, если пользователь регистрируется на сайте, используя тот же адрес электронной почты? мы сообщаем им, что электронная почта уже существует (электронная почта от сторонней модели), или мы все еще регистрируем их на сайте, а затем объединяем эти учетные записи?
user962206
@ user962206 многие службы не предоставят вам «настоящий» адрес электронной почты в любом случае по соображениям конфиденциальности. Например, Twitter не даст вам никакого адреса электронной почты, насколько я знаю, Facebook даст "user.name@facebook.com", который, я сомневаюсь, кто-то использовал бы для регистрации.
Капекс
44

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

Я вижу, что это жизнеспособный вариант, но, опять же, это зависит от ваших предпочтений по слиянию. Адрес электронной почты - это основной способ, с помощью которого люди проверяют некоторые важные изменения информации на вашем сайте, такие как изменение пароля, прекращение обслуживания, низкий уровень остатка на счете и т. Д. Это почти похоже на систему нумерации социальных сетей в Интернете, но с возможностью связи. , С культурной точки зрения: я думаю, что разумно предположить, что электронная почта является довольно уникальной личностью в службах аутентификации 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 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) Теперь вы вошли в учетную запись, которой вы доверяете, и сообщения электронной почты в ваших записях базы данных совпадают с теми, которым вы доверяете из внешних логинов.

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

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

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

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

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

Макс Александр
источник
1
Когда вы используете внешнюю схему аутентификации (Facebook, Google, Twitter и т. Д.), У вас никогда не будет доступа к паролю внешнего провайдера. Пароль в приведенном выше примере - это пароль для вашего СОБСТВЕННОГО веб-приложения.
Макс Александр
6
Twitter не предлагает пользователям электронную почту. После первой проверки подлинности, если идентификатор пользователя Twitter не существует, запросите у него адрес электронной почты и пароль. Если адрес электронной почты и пароль существуют, свяжите учетные записи. Если этого не произойдет, сохраните электронную почту и пароль для бесшовной последующей аутентификации. Это было полезно вообще?
Макс Александр
1
Как примечание, теперь возможно запросить разрешения для вашего приложения Twitter, чтобы получить адрес электронной почты пользователя.
Сунил Д.
2
Facebook заставляет людей проверять свою электронную почту? Я знаю, что Github, например, нет. Вредоносный пользователь может подписаться на Github с чужим именем электронной почты, а затем получить доступ к своей учетной записи на вашем сайте с помощью этой стратегии. (API Github сообщает вам, подтверждена ли их электронная почта или нет - вы можете отклонить проверку подлинности с помощью Github на непроверенном адресе электронной почты)
Matthew Moisen
6
Это нарушение безопасности, если пользователь регистрируется через социальные сети, редактирует свой адрес электронной почты в социальных сетях, кто-то другой берет тот же адрес электронной почты, регистрируется в социальных сетях, а затем входит в систему, они будут объединены с чужой учетной записью. Это очень маловероятно, но, тем не менее, является нарушением. Или я что-то упустил.
Шейн
35

Я прошел через это с 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 мы решили использовать "Нужна помощь при входе?" и когда вы нажимаете, спросите пользователя его адрес электронной почты или имя пользователя. Мы ищем его и, если найдем подходящую учетную запись, отправим пользователю по электронной почте ссылку, по которой он может автоматически войти в службу (на один раз). Оказавшись здесь, мы перенаправляем их прямо на страницу привязки учетных записей, говорим им, что они должны взглянуть и потенциально связывать дополнительные учетные записи, и показываем им сторонние учетные записи, которые они уже связали.

Эран Хаммер
источник
Это решение намного лучше для меня, спасибо!
Рой Шоа
2
Файл cookie сеанса недостаточно хорош для идентификации пользователя. Что если другой пользователь использует то же устройство?
DeepBlue
23

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

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

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

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

Брэд Дж
источник
что делать, если вы не получили адрес электронной почты от провайдера?
fred.kassi
1

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

galki
источник
Есть случаи, когда считается, что FireBase не имеет смысла. Например, интранет-системы, в которых зарегистрировано более одного входа.
Боствик,
-4

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

Нафтали ака Нил
источник
4
А что произойдет, если пользователь этого не сделает и обнаружит, что у него 4 разных аккаунта? Как вы создаете архитектуру, которая допускает слияние в этом случае?
Дэвид Бойк
В зависимости от ваших потребностей это может быть действительным предложением. Я просто хочу предупредить тех, кто думает, что объединение или связывание учетных записей может быть выполнено позже как последующий шаг: если вы считаете, что это то, что вы можете захотеть позже, тогда вы захотите подготовиться к этому в начале с дизайном вашей базы данных: вариант состоит в том, чтобы иметь UserGroup и UserMapping. Вы можете сопоставить идентификатор пользователя OAuth или идентификатор пользователя электронной почты и пароля с группой пользователей.
BumbleB2na