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
相关产品推荐
相关产品推荐

