קישור של כמה ספקים לחשבון אחד
במאמר הזה מוסבר איך לקשר כמה ספקים לחשבון אחד ב-Identity Platform.
ב-Identity Platform, המשתמשים מזוהים באמצעות מזהה ייחודי. כך המשתמשים יכולים להיכנס לאותו חשבון דרך ספקים שונים. לדוגמה, משתמש שנרשם בהתחלה עם מספר טלפון יכול לקשר את חשבון Google שלו מאוחר יותר, ואז להשתמש בכל אחת מהשיטות כדי להיכנס.
לפני שמתחילים
להוסיף לאפליקציה תמיכה בשני ספקי זהויות או יותר.
הפעלה או השבתה של קישור חשבונות
ההגדרה של קישור החשבון קובעת איך Identity Platform מטפלת במשתמשים שמנסים להיכנס עם אותה כתובת אימייל באמצעות ספקים שונים.
קישור חשבונות שמשתמשים באותו אימייל: Identity Platform תציג שגיאה אם משתמש ינסה להיכנס באמצעות אימייל שכבר נמצא בשימוש. האפליקציה יכולה לזהות את השגיאה הזו ולקשר את הספק החדש לחשבון הקיים.
יצירת כמה חשבונות לכל ספק זהויות: בכל פעם שמשתמש ייכנס באמצעות ספק אחר, ייווצר חשבון משתמש חדש ב-Identity Platform.
כדי לבחור הגדרה:
נכנסים לדף Settings של Identity Platform במסוףGoogle Cloud .
בוחרים הגדרה בקטע קישור חשבון משתמש.
לוחצים על Save.
קישור פרטי כניסה של ספק מאוחד
כדי לקשר פרטי כניסה מספק מאוחד:
מבצעים כניסה של המשתמש באמצעות ספק אימות או שיטת אימות כלשהם.
מקבלים את אובייקט הספק שתואם לספק שרוצים לקשר לחשבון המשתמש. לדוגמה:
גרסה 9 לאינטרנט
import { GoogleAuthProvider, FacebookAuthProvider, TwitterAuthProvider, GithubAuthProvider } from "firebase/auth"; const googleProvider = new GoogleAuthProvider(); const facebookProvider = new FacebookAuthProvider(); const twitterProvider = new TwitterAuthProvider(); const githubProvider = new GithubAuthProvider();
גרסה 8 לאינטרנט
var googleProvider = new firebase.auth.GoogleAuthProvider(); var facebookProvider = new firebase.auth.FacebookAuthProvider(); var twitterProvider = new firebase.auth.TwitterAuthProvider(); var githubProvider = new firebase.auth.GithubAuthProvider();
מבקשים מהמשתמש להיכנס באמצעות הספק שרוצים לקשר. אפשר לפתוח חלון קופץ או להפנות מחדש את הדף הנוכחי. הפניה אוטומטית קלה יותר למשתמשים במכשירים ניידים.
כדי להציג חלון קופץ, מפעילים את
linkWithPopup():גרסה 9 לאינטרנט
import { getAuth, linkWithPopup, GoogleAuthProvider } from "firebase/auth"; const provider = new GoogleAuthProvider(); const auth = getAuth(); linkWithPopup(auth.currentUser, provider).then((result) => { // Accounts successfully linked. const credential = GoogleAuthProvider.credentialFromResult(result); const user = result.user; // ... }).catch((error) => { // Handle Errors here. // ... });
גרסה 8 לאינטרנט
auth.currentUser.linkWithPopup(provider).then((result) => { // Accounts successfully linked. var credential = result.credential; var user = result.user; // ... }).catch((error) => { // Handle Errors here. // ... });
כדי להפנות את הדף, קודם צריך להפעיל את
linkWithRedirect():פועלים לפי השיטות המומלצות כשמשתמשים ב-
signInWithRedirect, ב-linkWithRedirectאו ב-reauthenticateWithRedirect.גרסה 9 לאינטרנט
import { getAuth, linkWithRedirect, GoogleAuthProvider } from "firebase/auth"; const provider = new GoogleAuthProvider(); const auth = getAuth(); linkWithRedirect(auth.currentUser, provider) .then(/* ... */) .catch(/* ... */);
גרסה 8 לאינטרנט
auth.currentUser.linkWithRedirect(provider) .then(/* ... */) .catch(/* ... */);
אחרי שהמשתמש ייכנס לחשבון, הוא יופנה חזרה לאפליקציה. לאחר מכן, תוכלו לאחזר את תוצאת הכניסה באמצעות קריאה ל-
getRedirectResult():גרסה 9 לאינטרנט
import { getRedirectResult } from "firebase/auth"; getRedirectResult(auth).then((result) => { const credential = GoogleAuthProvider.credentialFromResult(result); if (credential) { // Accounts successfully linked. const user = result.user; // ... } }).catch((error) => { // Handle Errors here. // ... });
גרסה 8 לאינטרנט
auth.getRedirectResult().then((result) => { if (result.credential) { // Accounts successfully linked. var credential = result.credential; var user = result.user; // ... } }).catch((error) => { // Handle Errors here. // ... });
החשבון של המשתמש אצל ספק הזהויות המאוחד מקושר עכשיו לחשבון שלו ב-Identity Platform, והוא יכול להשתמש בספק כדי להיכנס.
קישור פרטי כניסה של כתובת אימייל וסיסמה
כדי להוסיף כתובת אימייל וסיסמה לחשבון משתמש קיים:
מעבירים את המשתמש לתהליך כניסה באמצעות ספק זהויות או שיטה כלשהם.
מבקשים מהמשתמש להזין כתובת אימייל וסיסמה.
יוצרים אובייקט
AuthCredentialעם כתובת האימייל והסיסמה:גרסה 9 לאינטרנט
import { EmailAuthProvider } from "firebase/auth"; const credential = EmailAuthProvider.credential(email, password);
גרסה 8 לאינטרנט
var credential = firebase.auth.EmailAuthProvider.credential(email, password);
מעבירים את האובייקט
AuthCredentialל-methodlinkWithCredential()של המשתמש שמחובר לחשבון:גרסה 9 לאינטרנט
import { getAuth, linkWithCredential } from "firebase/auth"; const auth = getAuth(); linkWithCredential(auth.currentUser, credential) .then((usercred) => { const user = usercred.user; console.log("Account linking success", user); }).catch((error) => { console.log("Account linking error", error); });
גרסה 8 לאינטרנט
auth.currentUser.linkWithCredential(credential) .then((usercred) => { var user = usercred.user; console.log("Account linking success", user); }).catch((error) => { console.log("Account linking error", error); });
פרטי הכניסה של כתובת האימייל והסיסמה מקושרים עכשיו לחשבון של המשתמש ב-Identity Platform, והוא יכול להשתמש בהם כדי להיכנס.
שימו לב שאפשר לקשר פרטי כניסה של ספק מאוחד לחשבון עם כתובת אימייל וסיסמה, גם אם כתובת האימייל שונה. במקרה כזה, אפשר להשתמש בכתובת האימייל שתואמת לספק המאוגד כדי ליצור חשבון נפרד עם כתובת אימייל וסיסמה.
טיפול בשגיאה "החשבון קיים עם פרטי כניסה אחרים"
אם הפעלתם את ההגדרה קישור חשבונות שמשתמשים באותה כתובת אימייל במסוףGoogle Cloud , כשמשתמש ינסה להיכנס לספק עם כתובת אימייל שכבר קיימת אצל ספק אחר (כמו Google), הפעולה תיכשל עם השגיאה auth/account-exists-with-different-credential ואובייקט AuthCredential.
כדי לטפל בשגיאה הזו, צריך לבקש מהמשתמש להיכנס באמצעות הספק הקיים.
ואז קוראים ל-linkWithCredential(), ל-linkWithPopup() או ל-linkWithRedirect() כדי לשייך את הספק החדש לחשבון באמצעות AuthCredential.
בדוגמה הבאה מוסבר איך לטפל בשגיאה הזו כשמשתמש מנסה להיכנס באמצעות פייסבוק:
גרסה 9 לאינטרנט
import { signInWithPopup, signInWithEmailAndPassword, linkWithCredential, FacebookAuthProvider } from "firebase/auth"; // User tries to sign in with Facebook. signInWithPopup(auth, facebookProvider).catch((error) => { // User's email already exists. if (error.code === 'auth/account-exists-with-different-credential') { // The pending Facebook credential. const pendingCred = FacebookAuthProvider.credentialFromError(error); // The provider account's email address. const email = error.customData.email; // Present the user with a list of providers they might have // used to create the original account. // Then, ask the user to sign in with the existing provider. const method = promptUserForSignInMethod(); if (method === 'password') { // TODO: Ask the user for their password. // In real scenario, you should handle this asynchronously. const password = promptUserForPassword(); signInWithEmailAndPassword(auth, email, password).then((result) => { return linkWithCredential(result.user, pendingCred); }).then(() => { // Facebook account successfully linked to the existing user. goToApp(); }); return; } // All other cases are external providers. // Construct provider object for that provider. // TODO: Implement getProviderForProviderId. const provider = getProviderForProviderId(method); // At this point, you should let the user know that they already have an // account with a different provider, and validate they want to sign in // with the new provider. // Note: Browsers usually block popups triggered asynchronously, so in // real app, you should ask the user to click on a "Continue" button // that will trigger signInWithPopup(). signInWithPopup(auth, provider).then((result) => { // Note: Identity Platform doesn't control the provider's sign-in // flow, so it's possible for the user to sign in with an account // with a different email from the first one. // Link the Facebook credential. We have access to the pending // credential, so we can directly call the link method. linkWithCredential(result.user, pendingCred).then((userCred) => { // Success. goToApp(); }); }); } });
גרסה 8 לאינטרנט
// User tries to sign in with Facebook. auth.signInWithPopup(facebookProvider).catch((error) => { // User's email already exists. if (error.code === 'auth/account-exists-with-different-credential') { // The pending Facebook credential. const pendingCred = error.credential; // The provider account's email address. const email = error.email; // Present the user with a list of providers they might have // used to create the original account. // Then, ask the user to sign in with the existing provider. const method = promptUserForSignInMethod(); if (method === 'password') { // TODO: Ask the user for their password. // In real scenario, you should handle this asynchronously. const password = promptUserForPassword(); auth.signInWithEmailAndPassword(email, password).then((result) => { return result.user.linkWithCredential(pendingCred); }).then(() => { // Facebook account successfully linked to the existing user. goToApp(); }); return; } // All other cases are external providers. // Construct provider object for that provider. // TODO: Implement getProviderForProviderId. const provider = getProviderForProviderId(method); // At this point, you should let the user know that they already have an // account with a different provider, and validate they want to sign in // with the new provider. // Note: Browsers usually block popups triggered asynchronously, so in // real app, you should ask the user to click on a "Continue" button // that will trigger signInWithPopup(). auth.signInWithPopup(provider).then((result) => { // Note: Identity Platform doesn't control the provider's sign-in // flow, so it's possible for the user to sign in with an account // with a different email from the first one. // Link the Facebook credential. We have access to the pending // credential, so we can directly call the link method. result.user.linkWithCredential(pendingCred).then((userCred) => { // Success. goToApp(); }); }); } });
השימוש בהפניה אוטומטית דומה לשימוש בחלון קופץ, אבל צריך לשמור במטמון את פרטי הכניסה בהמתנה בין ההפניות האוטומטיות של הדפים (לדוגמה, באמצעות אחסון סשן).
שימו לב שספקים מסוימים, כמו Google ומיקרוסופט, משמשים גם כספקי זהויות באימייל וגם כספקי זהויות ברשתות חברתיות. ספקי אימייל נחשבים כסמכותיים לכל הכתובות שקשורות לדומיין האימייל שהם מארחים. כלומר, משתמש שנכנס באמצעות כתובת אימייל שמתארחת אצל אותו ספק אף פעם לא יקבל את השגיאה הזו (לדוגמה, כניסה באמצעות חשבון Google עם כתובת אימייל של @gmail.com, או כניסה באמצעות חשבון Microsoft עם כתובת אימייל של @live.com או @outlook.com).
כניסה באמצעות ספק מהימן (כמו SAML) לא תגרום לשגיאת auth/account-exists-with-different-credential.
אם בחשבון הקיים יש כתובת אימייל מאומתת, Identity Platform מקשרת באופן אוטומטי את הספק החדש לחשבון הקיים ושומרת את פרטי הכניסה הקיימים. אם לחשבון הקיים יש כתובת אימייל לא מאומתת (כמו חשבון עם כתובת אימייל או סיסמה לא מאומתות), הספק המהימן מחליף את החשבון הלא מאומת ומסיר את הסיסמה הקיימת ואת פרטי הכניסה של הספק הלא מאומת כדי למנוע השתלטות על החשבון.
מיזוג חשבונות באופן ידני
אם משתמש מנסה להיכנס באמצעות פרטי כניסה שכבר מקושרים לחשבון משתמש אחר דרך אותו ספק, השיטות המובנות של ה-SDK של הלקוח לקישור חשבונות ייכשלו. במצב כזה, תצטרכו למזג את החשבונות באופן ידני ואז למחוק את החשבון השני. לדוגמה:
גרסה 9 לאינטרנט
// Sign in first account.
const result1 = await signInWithCredential(auth, cred1);
const user1 = result1.user;
// Try to link a credential that belongs to an existing account
try {
await linkWithCredential(user1, cred2);
} catch (error) {
// cred2 already exists so an error is thrown.
const result2 = await signInWithCredential(auth, error.credential);
const user2 = result2.user;
// Merge the data.
mergeData(user1, user2);
// Delete one of the accounts, and try again.
await user2.delete();
// Linking now will work.
await linkWithCredential(user1, result2.credential);
}
גרסה 8 לאינטרנט
// Sign in first account.
const result1 = await auth.signInWithCredential(cred1);
const user1 = result1.user;
// Try to link a credential that belongs to an existing account
try {
await user1.linkWithCredential(cred2);
} catch (error) {
// cred2 already exists so an error is thrown.
const result2 = await auth.signInWithCredential(error.credential);
const user2 = result2.user;
// Merge the data.
mergeData(user1, user2);
// Delete one of the accounts, and try again.
await user2.delete();
// Linking now will work.
await user1.linkWithCredential(result2.credential);
}
ביטול הקישור של ספק
אתם יכולים לבטל את הקישור של ספק לחשבון של משתמש. המשתמש לא יוכל יותר לבצע אימות באמצעות הספק הזה.
כדי לבטל את הקישור של ספק, מעבירים את מזהה הספק ל-method unlink().
אפשר לקבל את מזהי הספקים של ספקי האימות שמקושרים למשתמש מהמאפיין providerData.
גרסה 9 לאינטרנט
import { getAuth, unlink } from "firebase/auth"; const auth = getAuth(); unlink(auth.currentUser, providerId).then(() => { // Auth provider unlinked from account // ... }).catch((error) => { // An error happened // ... });
גרסה 8 לאינטרנט
user.unlink(providerId).then(() => { // Auth provider unlinked from account // ... }).catch((error) => { // An error happened // ... });
המאמרים הבאים
- להוסיף לאפליקציה תמיכה בספקי זהויות שונים.
- איך מנהלים ספקים באופן פרוגרמטי