Facebook、Twitter、Githubなどの複数の異なる認証プロバイダーを使用してユーザーがFirebaseアプリケーションに対して認証できるようにしたいと考えています。認証されたら、使用した認証方法に関係なく、ユーザーが同じアカウントにアクセスできるようにします。
つまり、アプリ内で複数の認証メソッドを1つのアカウントにマージしたいと考えています。Firebaseアプリでこれを行うにはどうすればよいですか?
Facebook、Twitter、Githubなどの複数の異なる認証プロバイダーを使用してユーザーがFirebaseアプリケーションに対して認証できるようにしたいと考えています。認証されたら、使用した認証方法に関係なく、ユーザーが同じアカウントにアクセスできるようにします。
つまり、アプリ内で複数の認証メソッドを1つのアカウントにマージしたいと考えています。Firebaseアプリでこれを行うにはどうすればよいですか?
アップデート(20160521): Firebaseは、 Firebase Authentication製品のメジャーアップデートをリリースしました。これにより、1人のユーザーがサポートされているさまざまなプロバイダーのアカウントをリンクできるようになります。この機能の詳細については、iOS、Web、およびAndroidのドキュメントを参照してください。以下の答えは歴史的な理由で残されています。
コアFirebaseサービスは、認証のためのいくつかの方法を提供します: https ://www.firebase.com/docs/security/authentication.html
基本的に、Firebaseは認証に安全なJWTトークンを使用します。JWTトークンの生成につながるもの(独自のサーバーでJWTライブラリを使用するなど)はすべて、Firebaseに対してユーザーを認証するために機能するため、認証プロセスを完全に制御できます。
Firebaseは、これらのトークンを生成する1つの方法であるFirebase Simple Loginと呼ばれるサービスを提供します(これにより、Facebook、Twitterなどの認証が提供されます)。これは、サーバーなしですばやく起動して実行できるようにするための一般的な認証シナリオを対象としていますが、認証する唯一の方法ではなく、包括的なソリューションを目的としたものでもありません。
FirebaseSimpleLoginを使用して複数のプロバイダーでログインできるようにするための1つのアプローチは次のとおりです。
実際には、TwitterとFacebookの両方の認証を有効にする(またはユーザーが一方のアカウントでアカウントを作成し、後でもう一方を追加できるようにする)と仮定すると、セキュリティルールは次のようになります。
{
"users": {
"$userid": {
// Require the user to be logged in, and make sure their current credentials
// match at least one of the credentials listed below, unless we're creating
// a new account from scratch.
".write": "auth != null &&
(data.val() === null ||
(auth.provider === 'facebook' && auth.id === data.child('facebook/id').val() ||
(auth.provider === 'twitter' && auth.id === data.child('twitter/id').val()))"
}
},
"user-mappings": {
// Only allow users to read the user id mapping for their own account.
"facebook": {
"$fbuid": {
".read": "auth != null && auth.provider === 'facebook' && auth.id === $fbuid",
".write": "auth != null &&
(data.val() == null ||
root.child('users').child(data.val()).child('facebook-id').val() == auth.id)"
}
},
"twitter": {
"$twuid": {
".read": "auth != null && auth.provider === 'twitter' && auth.id === $twuid",
".write": "auth != null &&
(data.val() == null ||
root.child('users').child(data.val()).child('twitter-id').val() == auth.id)"
}
}
}
}
この例では、1つのグローバルユーザーID(任意のIDを選択できます)を保存し、Facebook、Twitterなどの認証メカニズム間のプライマリユーザーレコードへのマッピングを維持します。各ユーザーのログイン時に、ユーザーマッピングからプライマリユーザーレコードを取得し、そのIDをユーザーデータとアクションのプライマリストアとして使用します。上記はまた、ユーザーマッピングのデータを制限および検証して、/ users / $ userid /(facebook-id | twitter)の下に同じFacebook、TwitterなどのユーザーIDを既に持っている適切なユーザーのみがデータに書き込むことができるようにします。 -id | etc-id)。
この方法を使用すると、すばやく起動して実行できます。ただし、複雑なユースケースがあり、認証エクスペリエンスを完全に制御したい場合は、独自のサーバーで独自の認証コードを実行できます。everyauthやpassportなど、これを行うために使用できる便利なオープンソースライブラリがたくさんあります。
サードパーティの認証プロバイダーを使用して認証することもできます。たとえば、サーバー側のコードを記述しなくても、すぐに使用できる多種多様な統合を備えたSinglyを使用できます。
この投稿が何ヶ月も存在することは知っていますが、この問題に直面したとき、コードをより柔軟にするために多くの時間がかかりました。上記のAndrewコードに基づいて、コードを少し調整しました。
サンプルデータストア:
userMappings
|---facebook:777
| |---user:"123"
|---twitter:888
|---user:"123"
users
|---123
|---userMappings
|---facebook: "facebook:777"
|---twitter: "twitter:888"
セキュリティルール:
"userMappings": {
"$login_id": {
".read": "$login_id === auth.uid",
".write": "auth!== null && (data.val() === null || $login_id === auth.uid)"
}
},
"users": {
"$user_id": {
".read": "data.child('userMappings/'+auth.provider).val()===auth.uid",
".write": "auth!= null && (data.val() === null || data.child('userMappings/'+auth.provider).val()===auth.uid)"
}
}
したがって、 userMappingsは、Facebook、Twitterでログインしたときに最初に検索する情報です。userMappingsのユーザーは、ユーザーのメインアカウントを指します。したがって、FacebookまたはTwitterでログインした後、メインユーザーアカウントを検索できます。ユーザーでは、そのデータにアクセスできるuserMappingのリストを保持しています。
新しいユーザーを作成するときは、最初にユーザーにアカウントを作成する必要があります。ユーザー内のユーザーのIDは、必要なものであれば何でもかまいません。セキュリティルールを追加せずにGoogleやGithubなどのログイン方法を提供できるため、これは柔軟性があります。
これを処理するためのangularfireデコレータを作成しました:angularfire-multi-auth
私はかなりの時間をかけて良い解決策を考えてきましたが、IMHOがどのプロバイダーからでも登録できるようになるのは混乱を招きます。私のフロントエンドでは、常にメール登録を要求します。そのため、たとえば、FacebookやGoogle+でログインしているユーザーは、メールを通知したときに同じユーザーとしてログに記録されます。
このように、Kumaによって提案されたサンプルデータはuserMappingsを複製する必要はありません。
サンプルデータストア:
userMappings
|---facebook:777
| |---user:"123"
|---twitter:888
|---user:"123"
users
|---123
|---user data