Mit Mandantenfähigkeit authentifizieren
In diesem Dokument erfahren Sie, wie Sie Nutzer in einer Mehrmandantenfähigen Identity Platform-Umgebung authentifizieren.
Hinweis
Achten Sie darauf, dass Sie die Mandantenfähigkeit für Ihr Projekt aktiviert und Ihre Mandanten konfiguriert haben. Weitere Informationen dazu finden Sie unter Erste Schritte mit Mandantenfähigkeit.
Außerdem müssen Sie das Client SDK in Ihre App einfügen:
Rufen Sie in der Google Cloud Console die Seite „Identity Platform“ auf.
Zur Nutzerseite „Identity Platform“Klicken Sie rechts oben auf Einrichtungsdetails für die Anwendung.
Kopieren Sie den Code in Ihre Webanwendung. Zum Beispiel:
Webversion 9
import { initializeApp } from "firebase/app"; const firebaseConfig = { apiKey: "...", // By default, authDomain is '[YOUR_APP].firebaseapp.com'. // You may replace it with a custom domain. authDomain: '[YOUR_CUSTOM_DOMAIN]' }; const firebaseApp = initializeApp(firebaseConfig);
Web version 8
firebase.initializeApp({ apiKey: '...', // By default, authDomain is '[YOUR_APP].firebaseapp.com'. // You may replace it with a custom domain. authDomain: '[YOUR_CUSTOM_DOMAIN]' });
Mit Mandanten anmelden
Zur Anmeldung bei einem Mandanten muss die Mandanten-ID an das auth
-Objekt übergeben werden.
Beachten Sie, dass tenantId
beim Laden von Seiten nicht beibehalten wird.
Webversion 9
import { getAuth } from "firebase/auth"; const auth = getAuth(); const tenantId = "TENANT_ID1"; auth.tenantId = tenantId;
Web version 8
const tenantId = "TENANT_ID1"; firebase.auth().tenantId = tenantId;
Alle zukünftigen Anmeldeanfragen von dieser auth
-Instanz enthalten die Mandanten-ID (TENANT_ID1
im vorherigen Beispiel), bis Sie die Mandanten-ID ändern oder zurücksetzen.
Sie können mit mehreren Mandanten mit einzelnen oder mehreren auth
-Instanzen arbeiten.
Wenn Sie eine einzelne auth
-Instanz verwenden möchten, ändern Sie das Attribut tenantId
, wenn Sie zwischen Mandanten wechseln möchten. Wenn Sie zu IdPs auf Projektebene zurückkehren möchten, legen Sie für tenantId
den Wert null
fest:
Webversion 9
// One Auth instance // Switch to tenant1 auth.tenantId = "TENANT_ID1"; // Switch to tenant2 auth.tenantId = "TENANT_ID2"; // Switch back to project level IdPs auth.tenantId = null;
Web version 8
// One Auth instance // Switch to tenant1 firebase.auth().tenantId = "TENANT_ID1"; // Switch to tenant2 firebase.auth().tenantId = "TENANT_ID2"; // Switch back to project level IdPs firebase.auth().tenantId = null;
Wenn Sie mehrere Instanzen verwenden möchten, erstellen Sie für jeden Mandanten eine neue auth
-Instanz und weisen Sie ihnen unterschiedliche IDs zu:
Webversion 9
// Multiple Auth instances import { initializeApp } from "firebase/app"; import { getAuth } from "firebase/auth"; const firebaseApp1 = initializeApp(firebaseConfig1, 'app1_for_tenantId1'); const firebaseApp2 = initializeApp(firebaseConfig2, 'app2_for_tenantId2'); const auth1 = getAuth(firebaseApp1); const auth2 = getAuth(firebaseApp2); auth1.tenantId = "TENANT_ID1"; auth2.tenantId = "TENANT_ID2";
Webversion 8
// Multiple Auth instances firebase.initializeApp(config, 'app1_for_tenantId1'); firebase.initializeApp(config, 'app2_for_tenantId2'); const auth1 = firebase.app('app1').auth(); const auth2 = firebase.app('app2').auth(); auth1.tenantId = "TENANT_ID1"; auth2.tenantId = "TENANT_ID2";
Nach der Anmeldung bei einem Mandanten wird ein Mandantennutzer mit user.tenantId
auf diesen Mandanten zurückgegeben. Wenn Sie tenantId
auf der Instanz auth
später ändern, ändert sich das Attribut currentUser
nicht. Es verweist weiterhin auf denselben Nutzer wie der vorherige Mandanten.
Webversion 9
import { signInWithEmailAndPassword, onAuthStateChanged } from "firebase/auth"; // Switch to TENANT_ID1 auth.tenantId = 'TENANT_ID1'; // Sign in with tenant signInWithEmailAndPassword(auth, email, password) .then((userCredential) => { // User is signed in. const user = userCredential.user; // user.tenantId is set to 'TENANT_ID1'. // Switch to 'TENANT_ID2'. auth.tenantId = 'TENANT_ID2'; // auth.currentUser still points to the user. // auth.currentUser.tenantId is 'TENANT_ID1'. }); // You could also get the current user from Auth state observer. onAuthStateChanged(auth, (user) => { if (user) { // User is signed in. // user.tenantId is set to 'TENANT_ID1'. } else { // No user is signed in. } });
Webversion 8
// Switch to TENANT_ID1 firebase.auth().tenantId = 'TENANT_ID1'; // Sign in with tenant firebase.auth().signInWithEmailAndPassword(email, password) .then((result) => { const user = result.user; // user.tenantId is set to 'TENANT_ID1'. // Switch to 'TENANT_ID2'. firebase.auth().tenantId = 'TENANT_ID2'; // firebase.auth().currentUser still point to the user. // firebase.auth().currentUser.tenantId is 'TENANT_ID1'. }); // You could also get the current user from Auth state observer. firebase.auth().onAuthStateChanged((user) => { if (user) { // User is signed in. // user.tenantId is set to 'TENANT_ID1'. } else { // No user is signed in. } });
E-Mail-/Passwortkonten
Das folgende Beispiel zeigt, wie ein neuer Nutzer registriert wird:
Web version 9
import { createUserWithEmailAndPassword } from "firebase/auth"; auth.tenantId = 'TENANT_ID'; createUserWithEmailAndPassword(auth, email, password) .then((userCredential) => { // User is signed in. // userCredential.user.tenantId is 'TENANT_ID'. }).catch((error) => { // Handle / display error. // ... });
Web version 8
firebase.auth().tenantId = 'TENANT_ID'; firebase.auth().createUserWithEmailAndPassword(email, password) .then((result) => { // result.user.tenantId is 'TENANT_ID'. }).catch((error) => { // Handle error. });
So melden Sie einen vorhandenen Nutzer an:
Webversion 9
import { signInWithEmailAndPassword } from "firebase/auth"; auth.tenantId = 'TENANT_ID'; signInWithEmailAndPassword(auth, email, password) .then((userCredential) => { // User is signed in. // userCredential.user.tenantId is 'TENANT_ID'. }).catch((error) => { // Handle / display error. // ... });
Web version 8
firebase.auth().tenantId = 'TENANT_ID'; firebase.auth().signInWithEmailAndPassword(email, password) .then((result) => { // result.user.tenantId is 'TENANT_ID'. }).catch((error) => { // Handle error. });
SAML
Zur Anmeldung bei einem SAML-Anbieter instanziieren Sie eine SAMLAuthProvider
-Instanz mit der Anbieter-ID aus der Google Cloud Console:
Webversion 9
import { SAMLAuthProvider } from "firebase/auth"; const provider = new SAMLAuthProvider("saml.myProvider");
Webversion 8
const provider = new firebase.auth.SAMLAuthProvider('saml.myProvider');
Sie können entweder einen Pop-up- oder einen Weiterleitungsablauf verwenden, um sich beim SAML-Anbieter anzumelden.
Pop-up
Webversion 9
import { signInWithPopup } from "firebase/auth"; // Switch to TENANT_ID1. auth.tenantId = 'TENANT_ID1'; // Sign-in with popup. signInWithPopup(auth, provider) .then((userCredential) => { // User is signed in. const user = userCredential.user; // user.tenantId is set to 'TENANT_ID1'. // Provider data available from the result.user.getIdToken() // or from result.user.providerData }) .catch((error) => { // Handle / display error. // ... });
Webversion 8
// Switch to TENANT_ID1. firebase.auth().tenantId = 'TENANT_ID1'; // Sign-in with popup. firebase.auth().signInWithPopup(provider) .then((result) => { // User is signed in. // tenant ID is available in result.user.tenantId. // Identity provider data is available in result.additionalUserInfo.profile. }) .catch((error) => { // Handle error. });
Weiterleiten
Webversion 9
import { signInWithRedirect, getRedirectResult } from "firebase/auth"; // Switch to TENANT_ID1. auth.tenantId = 'TENANT_ID1'; // Sign-in with redirect. signInWithRedirect(auth, provider); // After the user completes sign-in and returns to the app, you can get // the sign-in result by calling getRedirectResult. However, if they sign out // and sign in again with an IdP, no tenant is used. getRedirectResult(auth) .then((result) => { // User is signed in. // The tenant ID available in result.user.tenantId. // Provider data available from the result.user.getIdToken() // or from result.user.providerData }) .catch((error) => { // Handle / display error. // ... });
Webversion 8
// Switch to TENANT_ID1. firebase.auth().tenantId = 'TENANT_ID1'; // Sign-in with redirect. firebase.auth().signInWithRedirect(provider); // After the user completes sign-in and returns to the app, you can get // the sign-in result by calling getRedirectResult. However, if they sign out // and sign in again with an IdP, no tenant is used. firebase.auth().getRedirectResult() .then((result) => { // User is signed in. // The tenant ID available in result.user.tenantId. // Identity provider data is available in result.additionalUserInfo.profile. }) .catch((error) => { // Handle error. });
In beiden Fällen müssen Sie die richtige Mandanten-ID für die Instanz auth
festlegen.
Link per E-Mail
Zum Initiieren des Authentifizierungsablaufs wird eine Schnittstelle angezeigt, in der der Nutzer aufgefordert wird, seine E-Mail-Adresse anzugeben, und dann sendSignInLinkToEmail
aufzurufen, um ihm einen Authentifizierungslink zu senden. Achten Sie darauf, dass Sie die richtige Mandanten-ID in der Instanz auth
festlegen, bevor Sie die E-Mail senden.
Webversion 9
import { sendSignInLinkToEmail } from "firebase/auth"; // Switch to TENANT_ID1 auth.tenantId = 'TENANT_ID1'; sendSignInLinkToEmail(auth, email, actionCodeSettings) .then(() => { // The link was successfully sent. Inform the user. // Save the email locally so you don't need to ask the user for it again // if they open the link on the same device. window.localStorage.setItem('emailForSignIn', email); }) .catch((error) => { // Handle / display error. // ... });
Webversion 8
// Switch to TENANT_ID1 firebase.auth().tenantId = 'TENANT_ID1'; firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings) .then(() => { // The link was successfully sent. Inform the user. // Save the email locally so you don't need to ask the user for it again // if they open the link on the same device. window.localStorage.setItem('emailForSignIn', email); }) .catch((error) => { // Some error occurred, you can inspect the code: error.code });
Um die Anmeldung auf der Landingpage abzuschließen, parsen Sie zuerst die Mandanten-ID aus dem E-Mail-Link und legen Sie sie in der Instanz auth
fest. Rufen Sie dann signInWithEmailLink
mit der E-Mail-Adresse des Nutzers und dem tatsächlichen E-Mail-Link auf, der den einmaligen Code enthält.
Webversion 9
import { isSignInWithEmailLink, parseActionCodeURL, signInWithEmailLink } from "firebase/auth"; if (isSignInWithEmailLink(auth, window.location.href)) { const actionCodeUrl = parseActionCodeURL(window.location.href); if (actionCodeUrl.tenantId) { auth.tenantId = actionCodeUrl.tenantId; } let email = window.localStorage.getItem('emailForSignIn'); if (!email) { // User opened the link on a different device. To prevent session fixation // attacks, ask the user to provide the associated email again. For example: email = window.prompt('Please provide your email for confirmation'); } // The client SDK will parse the code from the link for you. signInWithEmailLink(auth, email, window.location.href) .then((result) => { // User is signed in. // tenant ID available in result.user.tenantId. // Clear email from storage. window.localStorage.removeItem('emailForSignIn'); }); }
Web version 8
if (firebase.auth().isSignInWithEmailLink(window.location.href)) { const actionCodeUrl = firebase.auth.ActionCodeURL.parseLink(window.location.href); if (actionCodeUrl.tenantId) { firebase.auth().tenantId = actionCodeUrl.tenantId; } let email = window.localStorage.getItem('emailForSignIn'); if (!email) { // User opened the link on a different device. To prevent session fixation // attacks, ask the user to provide the associated email again. For example: email = window.prompt('Please provide your email for confirmation'); } firebase.auth().signInWithEmailLink(email, window.location.href) .then((result) => { // User is signed in. // tenant ID available in result.user.tenantId. }); }
Benutzerdefinierte Tokens erstellen
Das Erstellen eines benutzerdefinierten Tokens für mehrere Mandanten ist mit dem Erstellen eines regulären benutzerdefinierten Tokens identisch. Solange auf der Instanz auth
die richtige Mandanten-ID festgelegt wurde, wird dem resultierenden JWT eine Anforderung der obersten Ebene tenant_id
hinzugefügt.
Ausführliche Anleitungen zum Erstellen und Verwenden von benutzerdefinierten Tokens finden Sie unter Benutzerdefinierte Tokens erstellen.
Das folgende Beispiel zeigt, wie Sie mithilfe des Admin SDK ein benutzerdefiniertes Token erstellen:
Webversion 9
// Ensure you're using a tenant-aware auth instance const tenantManager = admin.auth().tenantManager(); const tenantAuth = tenantManager.authForTenant('TENANT_ID1'); // Create a custom token in the usual manner tenantAuth.createCustomToken(uid) .then((customToken) => { // Send token back to client }) .catch((error) => { console.log('Error creating custom token:', error); });
Webversion 8
// Ensure you're using a tenant-aware auth instance const tenantManager = admin.auth().tenantManager(); const tenantAuth = tenantManager.authForTenant('TENANT_ID1'); // Create a custom token in the usual manner tenantAuth.createCustomToken(uid) .then((customToken) => { // Send token back to client }) .catch((error) => { console.log('Error creating custom token:', error); });
Der folgende Code zeigt, wie Sie sich mit einem benutzerdefinierten Token anmelden:
Webversion 9
import { signInWithCustomToken } from "firebase/auth"; auth.tenantId = 'TENANT_ID1'; signInWithCustomToken(auth, token) .catch((error) => { // Handle / display error. // ... });
Webversion 8
firebase.auth().tenantId = 'TENANT_ID1'; firebase.auth().signInWithCustomToken(token) .catch((error) => { // Handle Errors here. const errorCode = error.code; const errorMessage = error.message; // ... });
Wenn die Mandanten-IDs nicht übereinstimmen, schlägt die Methode signInWithCustomToken()
fehl.
Anmeldedaten für mehrere Mandanten verknüpfen
Sie können andere Arten von Anmeldedaten mit einem vorhandenen mehrmandantenfähigen Nutzer mit mehreren Mandanten verknüpfen. Wenn sich ein Nutzer beispielsweise zuvor bei einem SAML-Anbieter auf einem Mandanten authentifiziert hat, können Sie die Anmeldung per E-Mail-Adresse und Passwort zu seinem bestehenden Konto hinzufügen, damit sich dieser mit beiden Methoden beim Mandaten anmelden kann.
Web version 9
import { signInWithPopup, EmailAuthProvider, linkWithCredential, SAMLAuthProvider, signInWithCredential } from "firebase/auth"; // Switch to TENANT_ID1 auth.tenantId = 'TENANT_ID1'; // Sign-in with popup signInWithPopup(auth, provider) .then((userCredential) => { // Existing user with e.g. SAML provider. const prevUser = userCredential.user; const emailCredential = EmailAuthProvider.credential(email, password); return linkWithCredential(prevUser, emailCredential) .then((linkResult) => { // Sign in with the newly linked credential const linkCredential = SAMLAuthProvider.credentialFromResult(linkResult); return signInWithCredential(auth, linkCredential); }) .then((signInResult) => { // Handle sign in of merged user // ... }); }) .catch((error) => { // Handle / display error. // ... });
Webversion 8
// Switch to TENANT_ID1 firebase.auth().tenantId = 'TENANT_ID1'; // Sign-in with popup firebase.auth().signInWithPopup(provider) .then((result) => { // Existing user with e.g. SAML provider. const user = result.user; const emailCredential = firebase.auth.EmailAuthProvider.credential(email, password); return user.linkWithCredential(emailCredential); }) .then((linkResult) => { // The user can sign in with both SAML and email/password now. });
Wenn Sie einen vorhandenen Nutzer mit mehreren Mandanten verknüpfen oder neu authentifizieren, wird auth.tenantId
ignoriert. Verwenden Sie user.tenantId
, um anzugeben, welcher Mandant verwendet werden soll. Dies gilt auch für andere APIs zur Nutzerverwaltung, z. B. updateProfile
und updatePassword
.
Fehler "account-exists-with-different-credential" bearbeiten
Wenn Sie in Ihrem Konto die Einstellung Konten verknüpfen, die dieselbe E-Mail-Adresse verwenden aktiviert haben,
Google Cloud Console, wenn ein Nutzer versucht, sich bei einem Anbieter anzumelden
(z. B. SAML) mit einer E-Mail-Adresse, die bereits für einen anderen Anbieter existiert (z. B.
Google) erhalten, wird der Fehler auth/account-exists-with-different-credential
(zusammen mit einem AuthCredential
-Objekt).
Um die Anmeldung mit dem gewünschten Anbieter abzuschließen, muss sich der Nutzer zuerst beim bestehenden Anbieter (Google) anmelden und dann eine Verknüpfung zum ehemaligen AuthCredential
(SAML) herstellen.
Sie können entweder einen Pop-up- oder einen Weiterleitungsablauf verwenden, um diesen Fehler zu beheben.
Pop-up
Web version 9
import { signInWithPopup, fetchSignInMethodsForEmail, linkWithCredential } from "firebase/auth"; // Step 1. // User tries to sign in to the SAML provider in that tenant. auth.tenantId = 'TENANT_ID'; signInWithPopup(auth, samlProvider) .catch((error) => { // An error happened. if (error.code === 'auth/account-exists-with-different-credential') { // Step 2. // User's email already exists. // The pending SAML credential. const pendingCred = error.credential; // The credential's tenantId if needed: error.tenantId // The provider account's email address. const email = error.customData.email; // Get sign-in methods for this email. fetchSignInMethodsForEmail(email, auth) .then((methods) => { // Step 3. // Ask the user to sign in with existing Google account. if (methods[0] == 'google.com') { signInWithPopup(auth, googleProvider) .then((result) => { // Step 4 // Link the SAML AuthCredential to the existing user. linkWithCredential(result.user, pendingCred) .then((linkResult) => { // SAML account successfully linked to the existing // user. goToApp(); }); }); } }); } });
Web version 8
// Step 1. // User tries to sign in to the SAML provider in that tenant. firebase.auth().tenantId = 'TENANT_ID'; firebase.auth().signInWithPopup(samlProvider) .catch((error) => { // An error happened. if (error.code === 'auth/account-exists-with-different-credential') { // Step 2. // User's email already exists. // The pending SAML credential. const pendingCred = error.credential; // The credential's tenantId if needed: error.tenantId // The provider account's email address. const email = error.email; // Get sign-in methods for this email. firebase.auth().fetchSignInMethodsForEmail(email) .then((methods) => { // Step 3. // Ask the user to sign in with existing Google account. if (methods[0] == 'google.com') { firebase.auth().signInWithPopup(googleProvider) .then((result) => { // Step 4 // Link the SAML AuthCredential to the existing user. result.user.linkWithCredential(pendingCred) .then((linkResult) => { // SAML account successfully linked to the existing // user. goToApp(); }); }); } }); } });
Weiterleiten
Bei Verwendung von
signInWithRedirect
werdenauth/account-exists-with-different-credential
nach Abschluss des Weiterleitungsablaufs ingetRedirectResult
ausgelöst.Das Fehlerobjekt enthält das Attribut
error.tenantId
. Da die Mandanten-ID auf der Instanzauth
nach dem Weiterleiten nicht beibehalten wird, müssen Sie die Mandanten-ID aus dem Fehlerobjekt auf die Instanzauth
festlegen.Im folgenden Beispiel wird gezeigt, wie der Fehler behandelt wird:
Web version 9
import { signInWithRedirect, getRedirectResult, fetchSignInMethodsForEmail, linkWithCredential } from "firebase/auth"; // Step 1. // User tries to sign in to SAML provider. auth.tenantId = 'TENANT_ID'; signInWithRedirect(auth, samlProvider); var pendingCred; // Redirect back from SAML IDP. auth.tenantId is null after redirecting. getRedirectResult(auth).catch((error) => { if (error.code === 'auth/account-exists-with-different-credential') { // Step 2. // User's email already exists. const tenantId = error.tenantId; // The pending SAML credential. pendingCred = error.credential; // The provider account's email address. const email = error.customData.email; // Need to set the tenant ID again as the page was reloaded and the // previous setting was reset. auth.tenantId = tenantId; // Get sign-in methods for this email. fetchSignInMethodsForEmail(auth, email) .then((methods) => { // Step 3. // Ask the user to sign in with existing Google account. if (methods[0] == 'google.com') { signInWithRedirect(auth, googleProvider); } }); } }); // Redirect back from Google. auth.tenantId is null after redirecting. getRedirectResult(auth).then((result) => { // Step 4 // Link the SAML AuthCredential to the existing user. // result.user.tenantId is 'TENANT_ID'. linkWithCredential(result.user, pendingCred) .then((linkResult) => { // SAML account successfully linked to the existing // user. goToApp(); }); });
Web version 8
// Step 1. // User tries to sign in to SAML provider. firebase.auth().tenantId = 'TENANT_ID'; firebase.auth().signInWithRedirect(samlProvider); var pendingCred; // Redirect back from SAML IDP. auth.tenantId is null after redirecting. firebase.auth().getRedirectResult().catch((error) => { if (error.code === 'auth/account-exists-with-different-credential') { // Step 2. // User's email already exists. const tenantId = error.tenantId; // The pending SAML credential. pendingCred = error.credential; // The provider account's email address. const email = error.email; // Need to set the tenant ID again as the page was reloaded and the // previous setting was reset. firebase.auth().tenantId = tenantId; // Get sign-in methods for this email. firebase.auth().fetchSignInMethodsForEmail(email) .then((methods) => { // Step 3. // Ask the user to sign in with existing Google account. if (methods[0] == 'google.com') { firebase.auth().signInWithRedirect(googleProvider); } }); } }); // Redirect back from Google. auth.tenantId is null after redirecting. firebase.auth().getRedirectResult().then((result) => { // Step 4 // Link the SAML AuthCredential to the existing user. // result.user.tenantId is 'TENANT_ID'. result.user.linkWithCredential(pendingCred) .then((linkResult) => { // SAML account successfully linked to the existing // user. goToApp(); }); });
Erstellen und Löschen von Endnutzerkonten deaktivieren
Es gibt Situationen, in denen Sie möchten, dass Administratoren Nutzerkonten erstellen, anstatt dass die Konten durch Nutzeraktionen erstellt werden. In diesen Fällen können Sie Nutzeraktionen über unsere REST API deaktivieren:
curl --location --request PATCH 'https://identitytoolkit.googleapis.com/v2/projects/PROJECT_ID/tenants/TENANT_ID?updateMask=client' \ --header 'Authorization: Bearer AUTH_TOKEN' \ --header 'Content-Type: application/json' \ --data-raw '{ "client": { "permissions": { "disabled_user_signup": true, "disabled_user_deletion": true } } }'
Ersetzen Sie Folgendes:
AUTH_TOKEN
: Das Authentifizierungstoken.PROJECT_ID
: Projekt-ID.TENANT_ID
: die Mandanten-ID.
Nächste Schritte
- Anmeldeseite für mehrere Mandanten erstellen
- Vorhandene Nutzer zu einem Mandanten migrieren
- Mandanten programmatisch verwalten