קישור של כמה ספקים לחשבון
במאמר הזה מוסבר איך לקשר כמה ספקים לחשבון 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לשיטהlinkWithCredential()של המשתמש המחובר:גרסה 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 של המשתמש, והוא יכול להשתמש בהם כדי להיכנס לחשבון.
שימו לב שאפשר לקשר אישורים של ספק מאוחד לחשבון עם כתובת אימייל וסיסמה שונות. אם זה קורה, אפשר להשתמש בכתובת האימייל שמתאימה לספק המאוחד כדי ליצור חשבון נפרד עם כתובת אימייל וסיסמה.
טיפול בשגיאה account-exists-with-different-credential
אם הפעלתם את ההגדרה קישור חשבונות שמשתמשים באותה כתובת אימייל ב-Google Cloud console, כשמשתמש מנסה להיכנס לספק (למשל SAML) עם כתובת אימייל שכבר קיימת אצל ספק אחר (למשל Google), מוצגת השגיאה auth/account-exists-with-different-credential (יחד עם אובייקט AuthCredential).
כדי לטפל בשגיאה הזו, צריך לבקש מהמשתמש להיכנס באמצעות הספק הקיים.
לאחר מכן, מתקשרים למספר linkWithCredential(), linkWithPopup() או linkWithRedirect() כדי לשייך את הספק החדש לחשבון באמצעות AuthCredential.
בדוגמה הבאה מוצג איך לטפל בשגיאה הזו כשמשתמש מנסה להיכנס באמצעות פייסבוק:
גרסה 9 לאינטרנט
import { signInWithPopup, signInWithEmailAndPassword, linkWithCredential } 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 = error.credential; // 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, או כניסה לחשבון מיקרוסופט באמצעות כתובת אימייל של @live.com או @outlook.com).
מיזוג חשבונות באופן ידני
אם משתמש מנסה להיכנס באמצעות פרטי כניסה שכבר מקושרים לחשבון משתמש אחר באותו ספק, השיטות המובנות של 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);
}
ביטול הקישור של ספק
אפשר לבטל את הקישור של ספק לחשבון של משתמש. המשתמש לא יוכל יותר לבצע אימות באמצעות הספק הזה.
כדי לבטל את הקישור של ספק, מעבירים את מזהה הספק לשיטה 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 // ... });
המאמרים הבאים
- הוספת תמיכה בספקי זהויות שונים לאפליקציה.
- איך מנהלים ספקים באמצעות תכנות