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:

  1. Rufen Sie in der Cloud Console die Seite „Identity Platform“ auf.
    Zur Nutzerseite „Identity Platform“

  2. Klicken Sie rechts oben auf Einrichtungsdetails für die Anwendung.

  3. Kopieren Sie den Code in Ihre Webanwendung. Zum Beispiel:

    <script src="https://www.gstatic.com/firebasejs/x.x.x/firebase.js"></script>
    <script>
    // Initialize Identity Platform
    const config = {
      apiKey: "...",
      authDomain: "my-app-12345.firebaseapp.com"
    };
    firebase.initializeApp(config);
    </script>
    

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.

var 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:

// One Auth instance
// Switch to tenant1
firebase.auth().tenantId = 'tenant1';
// Switch to tenant2
firebase.auth().tenantId = 'tenant2';
// 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:

// 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 = 'tenant1';
auth2.tenantId = 'tenant2';

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.

// 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:

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:

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 Cloud Console:

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.

Das folgende Beispiel zeigt den Pop-up-Ablauf:

// 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.
  });

Weiterleitung

Das folgende Beispiel zeigt den Weiterleitungsablauf:

// 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.

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.

// Switch to TENANT_ID1
firebase.auth().tenantId = 'TENANT_ID1';

firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings)
  .then(function() {
    // 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(function(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.

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:

// 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:

firebase.auth().tenantId = 'TENANT_ID1';

firebase.auth().signInWithCustomToken(token)
  .catch((error) => {
    // Handle Errors here.
    var errorCode = error.code;
    var 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.

// Switch to TENANT_ID1
firebase.auth().tenantId = 'TENANT_ID1';

//Sign-in with popup
firebase.auth().signInWithPopup(provider)
  .then((result) => {
    // Existing user with 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 der Cloud Console die Einstellung Konten mit derselben E-Mail-Adresse verknüpfen aktiviert haben und ein Nutzer versucht, sich bei einem Anbieter (z. B. SAML) mit einer E-Mail-Adresse anzumelden, die bereits für einen anderen Anbieter (z. B. Google) vorhanden ist, wird der Fehler auth/account-exists-with-different-credential zusammen mit einem AuthCredential-Objekt ausgelöst.

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.

Das folgende Beispiel zeigt, wie mit Fehler vom Typ auth/account-exists-with-different-credential umgegangen wirdhändelt werden, wenn signInWithPopup verwendet wird:

// 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.
      var pendingCred = error.credential;
      // The credential's tenantId if needed: error.tenantId
      // The provider account's email address.
      var 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(function(linkResult) {
                    // SAML account successfully linked to the existing
                    // user.
                    goToApp();
                  });
              });
          }
        });
    }
  });

Weiterleitung

Bei Verwendung von signInWithRedirect werden auth/account-exists-with-different-credential nach Abschluss des Weiterleitungsablaufs in getRedirectResult ausgelöst.

Das Fehlerobjekt enthält das Attribut error.tenantId. Da die Mandanten-ID auf der Instanz auth nach dem Weiterleiten nicht beibehalten wird, müssen Sie die Mandanten-ID aus dem Fehlerobjekt auf die Instanz auth festlegen.

Im folgenden Beispiel wird gezeigt, wie der Fehler behandelt wird:

// Step 1.
// User tries to sign in to SAML provider.
firebase.auth().tenantId = 'TENANT_ID';
firebase.auth().signInWithRedirect(samlProvider);
// 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.
    var tenantId = error.tenantId;
    // The pending SAML credential.
    var pendingCred = error.credential;
    // The provider account's email address.
    var 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(function(linkResult) {
      // SAML account successfully linked to the existing
      // user.
      goToApp();
    });
});

Nächste Schritte