Menautkan beberapa penyedia ke satu akun
Dokumen ini menunjukkan cara menautkan beberapa penyedia ke satu akun Identity Platform.
Identity Platform menggunakan ID unik untuk mengidentifikasi pengguna. Hal ini memungkinkan pengguna login ke akun yang sama dengan penyedia yang berbeda. Misalnya, pengguna yang awalnya mendaftar dengan nomor telepon dapat menautkan Akun Google mereka nanti, lalu menggunakan salah satu metode untuk login.
Sebelum memulai
Tambahkan dukungan untuk dua atau beberapa penyedia identitas ke aplikasi Anda.
Mengaktifkan atau menonaktifkan penautan akun
Setelan penautan akun menentukan cara Identity Platform menangani pengguna yang mencoba login dengan email yang sama menggunakan penyedia yang berbeda.
Tautkan akun yang menggunakan email yang sama: Identity Platform akan menampilkan error jika pengguna mencoba login dengan email yang sudah digunakan. Aplikasi Anda dapat menangkap error ini, dan menautkan penyedia baru ke akun yang sudah ada.
Membuat beberapa akun untuk setiap penyedia identitas: Akun pengguna Identity Platform baru akan dibuat setiap kali pengguna login dengan penyedia yang berbeda.
Untuk memilih setelan:
Buka halaman Settings Identity Platform di konsol Google Cloud.
Pilih setelan di bagian Penautan akun pengguna.
Klik Simpan.
Menautkan kredensial penyedia gabungan
Untuk menautkan kredensial dari penyedia gabungan:
Proses login pengguna dengan penyedia atau metode autentikasi apa pun.
Dapatkan objek penyedia yang sesuai dengan penyedia yang ingin Anda tautkan ke akun pengguna. Contoh:
Web versi 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();
Web versi 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();
Mintalah pengguna untuk login dengan penyedia yang ingin Anda tautkan. Anda dapat membuka jendela pop-up, atau mengalihkan halaman saat ini. Pengalihan lebih mudah bagi pengguna di perangkat seluler.
Untuk menampilkan pop-up, panggil
linkWithPopup()
:Web versi 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. // ... });
Web versi 8
auth.currentUser.linkWithPopup(provider).then((result) => { // Accounts successfully linked. var credential = result.credential; var user = result.user; // ... }).catch((error) => { // Handle Errors here. // ... });
Untuk mengalihkan halaman, panggil
linkWithRedirect()
terlebih dahulu:Ikuti praktik terbaik saat menggunakan
signInWithRedirect
,linkWithRedirect
, ataureauthenticateWithRedirect
.Web versi 9
import { getAuth, linkWithRedirect, GoogleAuthProvider } from "firebase/auth"; const provider = new GoogleAuthProvider(); const auth = getAuth(); linkWithRedirect(auth.currentUser, provider) .then(/* ... */) .catch(/* ... */);
Web versi 8
auth.currentUser.linkWithRedirect(provider) .then(/* ... */) .catch(/* ... */);
Setelah login, pengguna akan dialihkan kembali ke aplikasi Anda. Kemudian, Anda dapat mengambil hasil login dengan memanggil
getRedirectResult()
:Web versi 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. // ... });
Web versi 8
auth.getRedirectResult().then((result) => { if (result.credential) { // Accounts successfully linked. var credential = result.credential; var user = result.user; // ... } }).catch((error) => { // Handle Errors here. // ... });
Akun pengguna dengan penyedia gabungan kini ditautkan ke akun Identity Platform-nya, dan dia dapat menggunakan penyedia tersebut untuk login.
Menautkan kredensial email dan sandi
Untuk menambahkan alamat email dan sandi ke akun pengguna yang ada:
Proses login pengguna dengan penyedia atau metode identitas apa pun.
Mintalah pengguna mengisi alamat email dan sandi.
Buat objek
AuthCredential
dengan alamat email dan sandi tersebut:Web versi 9
import { EmailAuthProvider } from "firebase/auth"; const credential = EmailAuthProvider.credential(email, password);
Web versi 8
var credential = firebase.auth.EmailAuthProvider.credential(email, password);
Teruskan objek
AuthCredential
ke metodelinkWithCredential()
pada pengguna yang login:Web versi 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); });
Web versi 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); });
Kredensial email dan sandi kini ditautkan ke akun Identity Platform pengguna, dan mereka dapat menggunakannya untuk login.
Perhatikan bahwa kredensial penyedia gabungan dapat ditautkan ke akun email/sandi dengan email yang berbeda. Jika hal ini terjadi, email yang sesuai dengan penyedia gabungan dapat digunakan untuk membuat akun email/sandi terpisah.
Menangani error account-exists-with-different-credential
Jika Anda mengaktifkan setelan Tautkan akun yang menggunakan email yang sama di konsol Google Cloud, saat pengguna mencoba login ke penyedia (seperti SAML) dengan email yang sudah ada untuk penyedia lain (seperti Google), error auth/account-exists-with-different-credential
akan ditampilkan (bersama dengan objek AuthCredential
).
Untuk menangani error ini, minta pengguna untuk login dengan penyedia yang ada.
Kemudian, panggil linkWithCredential()
, linkWithPopup()
, atau
linkWithRedirect()
untuk mengaitkan penyedia baru ke akun mereka menggunakan AuthCredential
.
Contoh berikut menunjukkan cara menangani error ini saat pengguna mencoba login menggunakan Facebook:
Web versi 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(); }); }); } });
Web versi 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(); }); }); } });
Menggunakan pengalihan mirip dengan pop-up, kecuali Anda harus meng-cache kredensial yang tertunda di antara pengalihan halaman (misalnya, dengan menggunakan penyimpanan sesi).
Perhatikan bahwa beberapa penyedia, seperti Google dan Microsoft, berfungsi sebagai penyedia email dan
identitas sosial. Penyedia email dianggap otoritatif untuk semua alamat yang terkait dengan domain email mereka yang dihosting. Artinya, pengguna yang login dengan alamat email yang dihosting oleh penyedia yang sama tidak akan pernah mengalami error ini (misalnya, login dengan Google menggunakan email @gmail.com
, atau Microsoft menggunakan email @live.com
atau @outlook.com
).
Menggabungkan akun secara manual
Jika pengguna mencoba login dengan kredensial yang sudah ditautkan ke akun pengguna lain menggunakan penyedia yang sama, metode bawaan SDK klien untuk penautan akun akan gagal. Dalam situasi ini, Anda harus menggabungkan akun secara manual, lalu menghapus akun kedua. Contoh:
Web versi 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);
}
Web versi 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);
}
Membatalkan tautan penyedia
Anda dapat membatalkan tautan penyedia dari akun pengguna. Pengguna tidak akan dapat lagi melakukan autentikasi dengan penyedia tersebut.
Untuk membatalkan tautan penyedia, teruskan ID penyedia ke metode unlink()
.
Anda dapat memperoleh ID penyedia autentikasi yang tertaut dengan pengguna dari properti providerData
.
Web versi 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 // ... });
Web versi 8
user.unlink(providerId).then(() => { // Auth provider unlinked from account // ... }).catch((error) => { // An error happened // ... });
Langkah selanjutnya
- Tambahkan dukungan untuk berbagai penyedia identitas ke aplikasi Anda.
- Pelajari cara mengelola penyedia secara terprogram.