Архітектура для об'єднання декількох облікових записів користувачів разом


176

Гаразд, у мене з’явився веб-сайт, де ви можете зареєструватися і увійти. Ви також можете увійти у свій акаунт у facebook, twitter або linkedin.

Важливо, щоб користувачі мали лише один обліковий запис. Тож якось хочеться злити облікові записи користувачів, якщо вони використовують різні методи для входу. Яке найкраще рішення для вирішення цього питання?

Наприклад, користувач входить у свій обліковий запис у Facebook. Я використовую дані, щоб автоматично зареєструвати його. Чи повинен я надіслати електронний лист із ім’ям користувача та паролем нашого веб-сайту? (Якщо це нормально з політикою Facebook). Чи повинен я дати їм другий екран, де вони можуть заповнити ім’я користувача та пароль? Але це не ідея входу в обліковий запис Facebook. Це має спростити вашу процедуру участі.

Можливо також, що користувач зареєструвався на нашому веб-сайті, і наступного разу, коли він ввійде в систему, використовуючи свій акаунт у Twitter. Як я можу об'єднати ці два рахунки як один? Який найкращий спосіб?

Тому в основному моє запитання таке: я отримав 4 різних способи користувач стати членом нашого веб-сайту. Як я можу переконатися, що всі ці 4 способи створити лише один обліковий запис, якщо користувач вирішив використовувати кілька способів? Який найкращий потік, щоб переконатися, що він не стане клопотом для самого користувача?


Редагувати:

Через 3 роки після того, як я поставив це запитання, я даю відповідь у серії статей: https://www.peternijssen.nl/social-network-authentication-setup/
https://www.peternijssen.nl/social- автентифікація мережі-google /
https://www.peternijssen.nl/social-network-authentication-merging-accounts/
https://www.peternijssen.nl/social-network-authentication-twitter-facebook/


7
Звичайно, найкраще спробувати запобігти користувачеві мати в першу чергу кілька облікових записів, дозволяючи кілька методів входу, наприклад, переповнення стека, але навіть SO має можливість модераторів об'єднувати облікові записи. Я пропоную щедроту для всіх, хто може описати архітектуру, щоб дозволити це. Має бути краще рішення, ніж "оновити пост набору UserID = 2, де UserID = 1"
Девід Бойк

електронна пошта та телефон можуть використовуватися як ключ злиття, будь-який інший?
Wuaner

Привіт, надане вами посилання, здається, не працює. Він переходить лише на домашню сторінку сайту
vigamage

Оновлено посилання. Статті, хоча 6 років.
PT

Відповіді:


120

Я стикаюся з точно таким же завданням на даний момент. Дизайн, який я розробив, досить простий, але він працює добре.

Основна ідея полягає в тому, що моделі локальної ідентичності веб-сайту та сторонніх ідентичностей сайтів залишаються ізольованими, але згодом пов'язані. Таким чином, кожен користувач, який входить на сайт, має локальну ідентичність, яка відображає будь-яку кількість сторонніх ідентифікацій сайту.

Місцевий запис ідентичності містить мінімум інформації - це може бути навіть одне поле - лише первинний ключ. (Для моєї заявки я не переймаюся електронною поштою, іменем або датою народження. Я просто хочу знати, що це людина, яка весь цей час входила в цей обліковий запис.)

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

Нарешті, я веду записи про те, які особисті сторони пов'язані з якою локальною ідентичністю. Для створення цих записів потік виглядає приблизно так:

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

Об’єднання облікових записів - це питання об'єднання кожного окремого поля локальної ідентичності (яке буде залежати від програми до програми, і повинно бути простим, якщо у ваших локальних записах ідентичності є лише кілька полів), а потім забезпечення пов'язаних сторонніх ідентичностей пов'язані з результативною локальною ідентичністю.


1
Це дуже хороше рішення (мені подобається ідея автоматичного виявлення зіткнення локальної ідентичності)! Мені цікаво, чи знайшли ви спосіб автоматичного входу користувача в "додаткові" акаунти, які пов'язані після першого входу в додаток. Чи повинен користувач повинен входити окремо у кожен обліковий запис кожного разу, коли він відвідує (якщо вже немає активного сеансу з цим провайдером)?
Олександра

@Alexandra Що ви маєте на увазі під "додатковими рахунками"? Ви запитуєте, що відбувається, коли користувач увійде в програму через декілька різних автентифікаторів, створюючи для них нову локальну ідентичність?
щока

Я думаю, це вимагає належного уточнення та власного запитання: stackoverflow.com/questions/11060368/…
Олександра,

3
Питання хоч, але що робити, якщо користувач зареєструється на сайті, використовуючи ту саму електронну адресу? ми спонукаємо їх, що електронний лист вже існує (електронна пошта, що надійшла від сторонньої моделі) чи ми все-таки реєструємо їх на сайті, а потім ми об’єднали ці акаунти?
user962206

@ user962206 багато служб так і не нададуть вам "справжню" електронну адресу з міркувань конфіденційності. Наприклад, Twitter не дасть вам жодної адреси електронної пошти, наскільки я знаю, Facebook дасть "user.name@facebook.com", яку я сумніваюся, хтось використає для реєстрації.
kapex

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 UserId не існує, запропонуйте йому електронну пошту та пароль. Якщо електронна адреса та пароль існують, зв’яжіть акаунти. Якщо цього немає, збережіть електронну пошту та пароль для безперервної подальшої автентифікації. Це взагалі було корисно?
Макс Олександр

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 ми вирішили використовувати "Потрібна допомога входу?" а після натискання запитайте у користувача його електронну пошту чи ім’я користувача. Ми шукаємо це, і якщо ми знайдемо відповідний обліковий запис, надішлемо цьому користувачеві посилання, яке може автоматично увійти в службу (добре на один раз). Після цього ми переносимо їх безпосередньо на сторінку посилання на обліковий запис, повідомляємо їм, що вони повинні переглянути і, можливо, зв’язати додаткові облікові записи, і покажемо їм сторонні облікові записи, з якими вони вже пов’язані.


Для мене це рішення набагато краще, дякую!
Roy Shoa

2
Сесійне cookie недостатньо добре для ідентифікації користувача. Що робити, якщо інший користувач використовує той самий пристрій?
DeepBlue

23

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

Моя рекомендація щодо зменшення вразливості полягає у тому, щоб вимагати від користувача аутентифікації з одним із відомих постачальників ідентичності перед виконанням об'єднання для перевірки особи користувача.

Приклад: Користувач A реєструється з особою Facebook. Десь пізніше вони повертаються на ваш сайт і намагаються отримати доступ з ідентифікатором Windows Live ID і розпочати процес реєстрації. Ваш сайт підкаже користувачеві A з ... Схоже, ви раніше зареєструвались у Facebook. Будь ласка, увійдіть у Facebook (надайте посилання), і ми можемо об'єднати ваш ідентифікатор Windows Live з вашим наявним профілем.

Інша альтернатива - зберігати спільну таємницю (пароль / особистий запитання) при первинній реєстрації, яку повинен надати користувач під час об'єднання ідентифікаційних даних, однак це поверне вас до справи зберігання загальних секретів. Це також означає, що вам доведеться керувати тим сценарієм, коли користувач не запам'ятовує загальний секрет і робочий процес, що йде разом з ним.


що робити, якщо ви не отримаєте електронну адресу від провайдера?
fred.kassi

1

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


Існують випадки використання, які вважають, що firebase не має сенсу. Наприклад, інтранет-системи, які мають більше одного входу ..
Bostwick,


-4

Ви повинні дозволити вхід з одного облікового запису, а тоді, коли увійдете в систему, дайте можливість додати інший інший обліковий запис для злиття з ним.


4
А що станеться, якщо користувач цього не зробить, і опиниться з чотирма різними обліковими записами? Як ви створюєте архітектуру, яка дозволяє об'єднувати в цьому випадку?
Девід Бойке

Залежно від ваших потреб це насправді може бути дійсною пропозицією. Я просто хочу попередити тих, хто думає, що об’єднання чи зв’язування облікових записів може бути зроблено пізніше, як потім: Якщо ви вважаєте, що це щось, що ви можете пізніше, то ви хочете підготуватися до цього, створивши свою базу даних: варіант - мати UserGroup та UserMapping. Ви можете зіставити ідентифікатор користувача OAuth або ідентифікатор користувача електронною поштою та паролем у групі UserGroup.
BumbleB2na
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.