You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase用户禁用时beforeSignIn未触发的问题及方案咨询

解决方案:区分平台封禁与用户自行禁用的Firebase登录拦截方案

核心思路是放弃使用Firebase控制台的原生账号禁用功能,全部通过自定义声明管理两种禁用状态,确保beforeSignIn云函数始终能拦截并处理登录请求,同时满足用户自行解禁的需求。

1. 定义两种自定义声明

新增两个独立的自定义声明,明确区分场景:

  • isPlatformBanned: 平台主动封禁用户,不可自行解除
  • isSelfDisabled: 用户自行禁用账号,可通过登录操作恢复

2. 修改beforeSignIn云函数

更新登录拦截逻辑,优先处理平台封禁,再自动恢复用户自行禁用的账号:

const admin = require('firebase-admin');
admin.initializeApp();

exports.beforeSignIn = functions.auth.user().beforeSignIn(async (user, context) => {
  const { isPlatformBanned, isSelfDisabled } = user.customClaims || {};

  // 平台封禁:直接拦截登录,返回对应提示
  if (isPlatformBanned) {
    throw new functions.https.HttpsError(
      'permission-denied',
      '该账号因违反服务条款被永久封禁'
    );
  }

  // 用户自行禁用:自动清除禁用状态,允许正常登录
  if (isSelfDisabled) {
    await admin.auth().setCustomUserClaims(user.uid, {
      ...user.customClaims,
      isSelfDisabled: false
    });
    // 若需要二次验证(比如邮箱OTP),可抛出特定错误让前端引导用户完成验证
    // throw new functions.https.HttpsError('requires-verification', '你的账号已自行禁用,请验证身份后恢复');
  }
});

3. 维护平台封禁的云函数

修改setBanStatus,添加管理员权限验证,确保只有平台管理员能设置平台封禁状态:

exports.setBanStatus = functions.https.onRequest(async (req, res) => {
  const { uid, isPlatformBanned } = req.body;

  // 验证调用者是否为管理员
  const callerUid = req.auth?.uid;
  if (!callerUid) {
    return res.status(401).json({ error: '未授权访问' });
  }
  const callerUser = await admin.auth().getUser(callerUid);
  if (!callerUser.customClaims?.isAdmin) {
    return res.status(403).json({ error: '无操作权限' });
  }

  try {
    // 保留用户原有自定义声明,避免覆盖其他配置
    const targetUser = await admin.auth().getUser(uid);
    await admin.auth().setCustomUserClaims(uid, {
      ...targetUser.customClaims,
      isPlatformBanned: isPlatformBanned
    });
    return res.json({ message: `用户 ${uid} 的平台封禁状态已更新` });
  } catch (error) {
    return res.status(500).json({ error: error.message });
  }
});

4. 新增用户自行禁用/解禁的函数

创建可由用户调用的云函数,允许用户自行切换账号禁用状态(仅能操作自己的账号):

exports.toggleSelfDisable = functions.https.onCall(async (data, context) => {
  // 验证用户已登录
  if (!context.auth) {
    throw new functions.https.HttpsError('unauthenticated', '请先登录');
  }

  const uid = context.auth.uid;
  const user = await admin.auth().getUser(uid);
  const currentSelfDisabled = user.customClaims?.isSelfDisabled || false;

  // 切换自行禁用状态
  await admin.auth().setCustomUserClaims(uid, {
    ...user.customClaims,
    isSelfDisabled: !currentSelfDisabled
  });

  return {
    message: currentSelfDisabled ? '账号已成功恢复' : '账号已自行禁用'
  };
});

方案优势

  • 完全通过自定义声明管理状态,避免原生禁用跳过beforeSignIn的问题
  • 明确区分平台封禁与用户自行禁用场景,逻辑清晰
  • 用户自行解禁无需管理员介入,登录时自动恢复(或可按需添加验证步骤)

内容的提问来源于stack exchange,提问作者Cedric Hadjian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 08:08:26