Firebase Authentication 触发器

您可以触发函数来响应 Firebase Authentication 用户账号的创建和删除事件。例如,如果用户刚在您的应用中创建了账号,您可以向其发送欢迎电子邮件。此页面上的示例执行的就是这一操作 - 在创建和删除账号时发送欢迎和告别电子邮件。

如需查看更多使用场景示例,请参阅“Cloud Functions 有哪些用途?”

在创建用户时触发函数

您可以使用 firebase-functions/v2/identity 子软件包中的 onUserCreated 事件处理脚本创建一个在创建 Authentication 用户时触发的函数:

const { onUserCreated } = require("firebase-functions/identity");
const { defineSecret } = require("firebase-functions/params");
const { logger } = require("firebase-functions");
const { sendWelcomeEmail } = require("./utils/myEmailService");

const emailApiKey = defineSecret("EMAIL_API_KEY");

exports.newUserWelcome = onUserCreated(
  { secrets: [emailApiKey] },
  async (event) => {
    const { uid, email, displayName } = event.data;

    if (!email) {
      logger.log(`User ${uid} does not have an email address.`);
      return;
    }

    await sendWelcomeEmail(email, displayName);
  },
);

在以下情况下,Authentication 账号会为 Cloud Functions 触发用户创建事件:

  • 用户创建了电子邮件账号和密码。
  • 用户首次通过联合身份提供方登录。
  • 开发者使用 Admin SDK 创建了一个账号。
  • 用户首次登录新的匿名身份验证会话。

用户首次使用自定义令牌登录时,系统不会触发 Cloud Functions 事件。

配置触发器选项和多租户

您可以通过将选项对象 (AuthOptions) 作为第一个参数传递给 onUserCreated 来配置函数:

/**
 * Sends a welcome email scoped to a specific tenant in Identity Platform.
 */
exports.sendWelcomeEmailToTenant = onUserCreated(
  {
    secrets: [emailApiKey],
    // Only trigger when a user is a member of this tenant
    tenantId: "my-tenant-id",
  },
  async (event) => {
    const { uid, email, displayName } = event.data;
    // Customize the email for this tenant
    await sendWelcomeEmail(email, displayName, event.tenantId);
  },
);
  /**
 * Sends a welcome email only to users not associated with any tenant.
 */
exports.sendWelcomeEmailNoTenant = onUserCreated(
  {
    secrets: [emailApiKey],
    // Only trigger when a user is NOT a member of a tenant
    tenantId: IS_NOT_TENANT,
  },
  async (event) => {
    const { email, displayName } = event.data;

    // Send a generic welcome email
    await sendWelcomeEmail(email, displayName);
  },
);

如果您的项目使用 Identity Platform 多租户,您可以限定触发器的范围:

  • 默认项目(无租户):将 tenantId 设置为 IS_NOT_TENANT,以便仅监听在默认项目中创建的用户。
  • 特定租户:提供租户的字符串 ID(例如 { tenantId: "tenant-id-1" }),以便仅监听在该租户中创建的用户。
  • 所有租户和用户:如果省略 tenantId,则该函数会在项目中的所有租户和默认项目用户发生用户创建事件时触发。

除了 tenantId 之外,您还可以指定标准的第 2 代配置选项,包括 regionconcurrencycpumemorytimeoutSecondsminInstancesmaxInstancessecrets

访问用户属性

通过返回给函数的用户数据,您可以访问新建用户的 UserRecord 对象中提供的用户属性列表(通过 event.data)。例如,您可以获取用户的电子邮件地址和显示名,如下所示:

const { uid, email, displayName } = event.data;

第 2 代中的身份验证触发器会接收 AuthEvent 对象。除了 event.data 之外,您还可以访问以下事件元数据:

  • event.id:事件的唯一标识符。
  • event.type:事件类型 (google.firebase.auth.user.v2.created)。
  • event.time:表示事件发生时间的 ISO 8601 时间戳。
  • event.project:Google Cloud 项目 ID。
  • event.tenantId:与用户关联的 Identity Platform 租户 ID(如果适用)。

在删除用户时触发函数

与在创建用户时触发函数一样,您也可以在删除用户时触发函数。使用 firebase-functions/v2/identity 中的 onUserDeleted 事件处理脚本,如下所示:

const { onUserDeleted } = require("firebase-functions/identity");
const { defineSecret } = require("firebase-functions/params");
const { logger } = require("firebase-functions");
const { sendGoodbyeEmail } = require("./utils/myEmailService");

const emailApiKey = defineSecret("EMAIL_API_KEY");

exports.deletedUserFarewell = onUserDeleted(
  { secrets: [emailApiKey] },
  async (event) => {
    const { uid, email, displayName } = event.data;
    if (!email) {
      logger.log(`User ${uid} does not have an email address.`);
      return;
    }

    await sendGoodbyeEmail(email, displayName);
  },
);

onUserCreated 类似,您可以配置 onUserDeleted,并使用 { tenantId: IS_NOT_TENANT } 等选项将触发器限制为仅适用于默认项目中的用户。

触发屏蔽函数

如果您已升级到 Firebase Authentication with Identity Platform,则可以使用屏蔽函数来扩展 Firebase Authentication

通过阻塞函数,您可以同步执行自定义代码,以修改用户注册或登录应用的结果。与在事件完成后异步运行的后台触发器不同,阻塞函数允许您禁止不符合特定标准的用户通过身份验证,或者首先对用户的信息和声明进行更新,然后再将此信息返回到您的客户端应用。

第 2 代触发器的最佳实践

在实现第 2 代身份验证触发器时,请牢记以下最佳实践:

  • 考虑并发:Cloud Functions(第 2 代)实例会处理并发请求(默认情况下,当 CPU ≥ 1 时,并发请求数为 80)。确保函数在并发执行之间不依赖于全局可变状态。
  • 设计时要考虑幂等性:第 2 代中的事件传送通过 Eventarc 实现,至少传送一次。确保您的函数是幂等的;例如,在执行副作用之前,验证是否已发送欢迎电子邮件或已初始化数据库条目。
  • 确定多租户函数的范围:如果您的应用使用 Identity Platform 多租户,请验证您的函数是否应处理所有租户的事件,还是仅处理特定租户的事件。使用 tenantId: IS_NOT_TENANT 可防止租户用户触发仅供主项目使用的函数。
  • 管理区域和资源分配:指定函数位置 (region),以最大限度地缩短身份验证提供程序与函数执行环境之间的网络延迟时间。