web-dev-qa-db-ja.com

複数のユーザーアカウントをマージするためのアーキテクチャ

さて、自分で登録してログインできるウェブサイトを手に入れました。 Facebook、Twitter、またはLinkedinアカウントでログインすることもできます。

ユーザーは1つのアカウントのみを登録することが重要です。どういうわけか、ユーザーが異なる方法でログインする場合、ユーザーのアカウントをマージしたいと思います。これを解決する最良の解決策は何ですか?

たとえば、ユーザーは自分のFacebookアカウントでログインします。データを使用して、彼のアカウントを自動的に登録します。 Webサイトのユーザー名とパスワードを記載した電子メールを送信する必要がありますか? (これがFacebookのポリシーで問題ない場合)。ユーザー名とパスワードを入力できる2つ目の画面を表示する必要がありますか?しかし、それはあなたのFacebookアカウントでログインする背後にある考え方ではありません。参加する手順を簡素化する必要があります。

また、ユーザーが自分のWebサイトに自分自身を登録し、次回Twitterアカウントでログインした可能性もあります。これら2つのアカウントを1つのアカウントとしてマージするにはどうすればよいですか?最善の方法は何ですか?

したがって、基本的に私の質問は次のとおりです。ユーザーが私たちのウェブサイトのメンバーになる4つの異なる方法を得た。ユーザーが複数の方法を使用することに決めた場合、これら4つの方法すべてが1つのアカウントのみを作成するようにするにはどうすればよいですか?ユーザー自身にとって面倒にならないようにするための最良のフローは何ですか?


編集:

この質問をした3年後、私は一連の記事で自分で答えを与えています。 http://www.sitepoint.com/series/using-social-networks-as-a-login-system/

169
P.T.

私は現時点でまったく同じタスクに直面しています。私が考え出したデザインはかなりシンプルですが、うまく機能しています。

中心的なアイデアは、ローカルサイトIDとサードパーティサイトIDのモデルは分離されたままですが、後でリンクされるということです。したがって、サイトにログインするすべてのユーザーは、任意の数のサードパーティのサイトIDにマップされるローカルIDを持っています。

ローカルIDレコードには、最小限の情報が含まれています。単一のフィールドであっても、主キーにすぎません。 (私のアプリケーションでは、ユーザーの電子メール、名前、または誕生日を気にしません-彼らがずっとこのアカウントにログインしている人であることを知りたいだけです。)

サードパーティのIDには、サードパーティとの認証にのみ関連する情報が含まれています。 OAuthの場合、これは通常、ユーザーID(ID、メール、ユーザー名など)とサービスID(どのサイトまたはサービスで認証されたかを示す)を意味します。データベース以外のアプリケーションの他の部分では、そのサービス識別子は、そのサービスから関連するユーザー識別子を取得するためのメソッドとペアになり、それが認証の実行方法です。 OpenIDの場合、認証方法がより一般化されていることを除いて、同じアプローチを採用します(異なるID URLを使用することを除いて、ほぼ常に同じプロトコルを実行できるため、それがサービス識別子です)。

最後に、どのサードパーティIDがどのローカルIDとペアになっているかの記録を保持します。これらのレコードを生成するには、フローは次のようになります。

  • ユーザーは、サードパーティのIDを使用して初めてログインします。ローカルIDレコードが作成され、次にサードパーティIDレコードが作成され、それらがペアになります。
  • コントロールパネルでは、ユーザーはサードパーティのサービスにログインしてアカウントをリンクできます。 (これがどのように機能するかはかなり簡単です。)
  • ユーザーが意図せずに複数のアカウントを作成するシナリオでは、ソリューションは非常に簡単です。ユーザーはいずれかのアカウントにログインしている間に、以前にサイトへのログインに使用した別のアカウントにログインします(上記のコントロールパネル機能を使用)。 Webサービスはこの衝突(ログインしたユーザーのローカルIDが、ログインしたばかりのサードパーティIDにリンクされているローカルIDと異なること)を検出し、ユーザーはアカウントのマージを求められます。

アカウントのマージは、ローカルIDの個々のフィールドをマージすることです(アプリケーションごとに異なるため、ローカルIDレコードにフィールドが2つしかない場合は簡単になります)。次に、リンクされたサードパーティIDを確認します。結果のローカルIDにリンクされます。

118
cheeken

emailが重複する結合要素として基づいて、多くのサイトがマージされる傾向があります。

これは実行可能なオプションであることがわかりますが、これもマージの方法に関するあなたの好みに依存します。電子メールアドレスは、パスワードの変更、サービスの終了、アカウントの残高が少ないなど、サイト上の重要な情報の変更を確認するために使用される主な方法です。これは、Webの社会保障番号システムに似ていますが、コミュニケーション機能があります。文化的に:メールはOAuth認証サービス全体で非常にユニークなアイデンティティであると仮定するのが合理的だと思います。

私の現在の思考プロセス。

ログインページには3つのオプションがあります

  • 自分のサイトのメンバーシップ
  • Facebookでログイン
  • グーグルでログイン

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     | "[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)他の時間にユーザーが戻ってきたが、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)これで、データベースエントリの電子メールが信頼できるアカウントにマージされました。これは、外部ログインから信頼したものと同じです。

したがって、後続のログインのために

では、最初に外部ログインがあり、その後、ユーザーがパスワードでログインできるようにしたい場合はどうでしょうか?

私はこれを行う2つの簡単な方法を見ます

  • アカウントが外部認証から作成される最初のログインで、アプリケーションへの最初のエントリを完了するためにパスワードを要求します

  • 彼らがすでにfacebookまたはgoogleを使用してすでに登録している場合、どういうわけかあなた自身のサイトの登録フォームを使用して登録したかった。入力した電子メールアドレスが既に存在するかどうかを検出し、パスワードの入力を求め、登録完了後に確認メールを送信します。

42
Max Alexander

Sled.comでこれを実行しました。アカウントの作成およびログイン用の複数のサードパーティアカウントのサポートに関して、ここには複数の問題があります。それらのいくつかは次のとおりです。

  • ローカルパスワードとサードパーティログインの両方をサポートする必要がありますか?

Sled.comの場合、追加する価値が小さく、パスワード入力フォームを保護するための追加コストのため、ローカルパスワードを削除することにしました。パスワードを破るための攻撃は数多く知られています。パスワードを導入する場合は、簡単に破れないようにする必要があります。また、それらが漏洩しないように、一方向ハッシュなどに保存する必要があります。

  • 複数のサードパーティアカウントをサポートする際にどの程度の柔軟性を許可しますか?

Facebook、Twitter、LinkedInの3つのログインプロバイダーを既に選択しているようです。 OAuthを使用し、明確に定義された信頼できるプロバイダーのセットで作業していることを意味します。OpenIDのファンではありません。残りの質問は、同じプロバイダーのパーティアカウント(たとえば、2つのTwitterアカウントがリンクされた1つのローカルアカウント)いいえと仮定しますが、そうする場合は、データモデルに対応する必要があります。

Sledでは、Facebook、Twitter、Yahoo!でのログインをサポートしています。各ユーザーアカウント内に、それぞれのキーを保存します:{"_id": "djdjd99dj"、 "yahoo": "dj39djdj"、Twitter: "3723828732"、 "facebook": "12837287"}。各サードパーティアカウントが単一のローカルアカウントにのみリンクできるように、一連の制約を設定します。

同じサードパーティプロバイダーから複数のアカウントを許可する場合は、リストまたは他の構造を使用して、それをサポートし、他のすべての制限を使用して一意性を確保する必要があります。

  • 複数のアカウントをリンクするには?

ユーザーが初めてサービスにサインアップすると、最初にサードパーティプロバイダーにアクセスし、確認済みのサードパーティIDを返します。次に、それらのローカルアカウントを作成し、必要な他の情報を収集します。電子メールアドレスを収集し、ローカルユーザー名を選択するように依頼します(他のプロバイダーからの既存のユーザー名をフォームに事前入力しようとします)。何らかの形のローカル識別子(電子メール、ユーザー名)を持つことは、後でアカウントを回復するために非常に重要です。

サーバーは、ブラウザに既存のアカウントのセッションCookie(有効または期限切れ)がなく、使用されているサードパーティアカウントが見つからない場合、これが初めてのログインであることを認識します。ユーザーにログインするだけでなく、既にアカウントを持っている場合は、代わりに既存のアカウントで一時停止してログインできるように、新しいアカウントを作成していることをユーザーに通知しようとします。

まったく同じフローを使用して追加のアカウントをリンクしますが、ユーザーが第三者から戻ってきたときに、有効なセッションCookieの存在を使用して、新しいアカウントをログインアクションにリンクする試みを区別します。各タイプのサードパーティアカウントを1つだけ許可し、既にリンクされている場合は、アクションをブロックします。新しいアカウントをリンクするためのインターフェースは、すでに(プロバイダーごとに)ある場合は無効になっていますが、万が一に備えて、問題になりません。

  • アカウントをマージする方法は?

ユーザーが既にローカルアカウントにリンクされている新しいサードパーティアカウントをリンクしようとした場合、2つのアカウントをマージすることを確認するようプロンプトを表示するだけです(データセットでこのようなマージを処理できると仮定すると、多くの場合、簡単に言います)完了よりも)​​。マージをリクエストするための特別なボタンを提供することもできますが、実際には、別のアカウントをリンクするだけです。

これは非常に単純な状態マシンです。ユーザーは、サードパーティのアカウントIDでサードパーティから戻ってきます。データベースは、次の3つの状態のいずれかになります。

  1. アカウントはローカルアカウントにリンクされ、セッションCookieは存在しません->ログイン
  2. アカウントはローカルアカウントにリンクされ、セッションCookieが存在します->マージ
  3. アカウントはローカルアカウントにリンクされておらず、セッションCookieは存在しません->サインアップ
  4. アカウントはローカルアカウントにリンクされておらず、セッションCookieが存在します->追加アカウントのリンク

    • サードパーティのプロバイダーでアカウントの回復を実行する方法は?

これはまだ実験的な領域です。ほとんどのサービスはサードパーティのアカウントの隣にローカルパスワードを提供するため、このための完璧なUXを見たことはありません。

Sledでは、「サインインのヘルプが必要ですか?」の使用を選択しました。クリックすると、ユーザーにメールまたはユーザー名を尋ねます。調べて、一致するアカウントが見つかったら、そのユーザーにサービスに自動的にログインできるリンクをメールで送信します(一度だけ有効です)。一度、それらをアカウントリンクページに直接移動し、確認して追加のアカウントをリンクする可能性があることを伝え、既にリンクしているサードパーティアカウントを表示します。

34
Eran Hammer

アカウントを自動マージするための両方のアプローチは、誰かがアカウントを乗っ取ることを可能にするかなり大きな脆弱性を残します。どちらも、登録ユーザーにマージオプションを提供するときに、ユーザーが自分が言うとおりの人物であると仮定しているようです。

この脆弱性を緩和するための推奨事項は、マージを実行してユーザーのIDを確認する前に、既知のIDプロバイダーの1つでユーザー認証を要求することです。

例:ユーザーAはFacebook IDで登録します。しばらくして、サイトに戻り、Windows Live IDを使用してアクセスを試み、登録プロセスを開始します。あなたのサイトは、ユーザーAにプロンプ​​トを表示します...以前にFacebookに登録したようです。 Facebookでログイン(リンクを提供)してください。WindowsLive IDを既存のプロファイルにマージできます。

別の方法は、IDをマージするときにユーザーが提供する必要がある初期登録に共有秘密(パスワード/個人の質問)を保存することですが、これにより共有秘密を保存するビジネスに戻ります。また、ユーザーが共有シークレットとそれに伴うワークフローを覚えていないシナリオを処理する必要があることも意味します。

21
Brad J

ほとんどの投稿はかなり古く、Googleの無料 Firebase Authentication サービスはまだ存在していなかったと思います。 OAuthで検証した後、OAuthトークンを渡し、参照用に保存できる一意のユーザーIDを取得します。サポートされているプロバイダーはGoogle、Facebook、Twitter、GitHubです。カスタムおよび匿名プロバイダーを登録します。

2
galki

上記の素晴らしい回答とリソース。私の貢献はここにまとめられています... https://github.com/JavascriptMick/learntree.org/blob/master/design/Schema.md

TLDR:別のアカウントおよび個人スキーマ。アカウント、メール、OAuthの2つのバリエーション。

アカウント-認証->個人

0