在多租户环境中对用户进行身份验证

本文档介绍如何在多租户 Identity Platform 环境中对用户进行身份验证。

准备工作

请确保您已为项目启用了多租户并配置了租户。如需了解具体方法,请参阅多租户使用入门

您还需要将 Client SDK 添加到您的应用中:

  1. 前往 Google Cloud 控制台中的 Identity Platform 页面。
    前往 Identity Platform 用户页面

  2. 点击右上角的应用设置详情

  3. 将代码复制到您的 Web 应用中。例如:

Web 版本 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 版本 8

firebase.initializeApp({
  apiKey: '...',
  // By default, authDomain is '[YOUR_APP].firebaseapp.com'.
  // You may replace it with a custom domain.
  authDomain: '[YOUR_CUSTOM_DOMAIN]'
});

使用租户登录

要登录到租户,需要将租户 ID 传递给 auth 对象。请注意,重新加载页面时不会保留 tenantId

Web 版本 9

import { getAuth } from "firebase/auth";
const auth = getAuth();
const tenantId = "TENANT_ID1";
auth.tenantId = tenantId;

Web 版本 8

const tenantId = "TENANT_ID1";
firebase.auth().tenantId = tenantId;

auth 实例以后发出的任何登录请求都将包含该租户 ID(在以上示例中为 TENANT_ID1),除非您更改或重置租户 ID。

您可以使用单个或多个 auth 实例处理多个租户。

如需使用单个 auth 实例,则每当您要在租户之间切换时,修改 tenantId 属性即可。要还原为项目级 IdP,请将 tenantId 设置为 null

Web 版本 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 版本 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;

如需使用多个实例,请为每个租户创建一个新的 auth 实例并为其分配不同的 ID:

Web 版本 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";

Web 版本 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";

通过租户登录后,系统将返回租户用户并将 user.tenantId 设置为该租户。请注意,如果您以后在 auth 实例上切换 tenantIdcurrentUser 属性不会发生变化;它仍将指向与之前的租户相同的用户。

Web 版本 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.
  }
});

Web 版本 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.
  }
});

电子邮件/密码账号

以下示例展示了如何注册新用户:

Web 版本 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 版本 8

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

firebase.auth().createUserWithEmailAndPassword(email, password)
  .then((result) => {
    // result.user.tenantId is 'TENANT_ID'.
  }).catch((error) => {
    // Handle error.
  });

让现有用户登录:

Web 版本 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 版本 8

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

firebase.auth().signInWithEmailAndPassword(email, password)
  .then((result) => {
    // result.user.tenantId is 'TENANT_ID'.
  }).catch((error) => {
    // Handle error.
  });

SAML

如需通过 SAML 提供商登录,请使用 Google Cloud 控制台中的提供商 ID 实例化 SAMLAuthProvider 实例:

Web 版本 9

import { SAMLAuthProvider } from "firebase/auth";

const provider = new SAMLAuthProvider("saml.myProvider");

Web 版本 8

const provider = new firebase.auth.SAMLAuthProvider('saml.myProvider');

然后,您可以使用弹出式窗口或重定向流程登录 SAML 提供商。

  • 弹出式窗口

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

    Web 版本 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.
      });

  • 重定向

    Web 版本 9

    import { signInWithRedirect