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

如何限制Firebase Phone Authentication仅允许已注册用户登录?

解决Firebase手机号登录自动注册问题:先检查用户是否已注册

Firebase默认会为未注册的手机号自动创建账号,要实现"先检查用户是否已注册,未注册则引导注册"的需求,可通过以下两种方案实现:

方案一:验证OTP后判断是否为新用户(前端快速实现)

利用Firebase用户元数据判断是否为首次登录:新用户的metadata.creationTime和metadata.lastSignInTime时间完全一致,老用户则存在差异。

修改你的verifyOTP函数,添加判断逻辑:

const verifyOTP = (e) => {
     let otp = e.target.value;
     setOtp(otp);
     if(otp.length === 6) {
        let confirmationResult = window.confirmationResult;
        confirmationResult.confirm(otp).then((result) => {
            const user = result.user;
            if(user != null){
                // 判断是否为首次登录(新用户)
                const isNewUser = user.metadata.creationTime === user.metadata.lastSignInTime;
                if(isNewUser) {
                    // 新用户引导至注册完善页面
                    console.log('请完善注册信息');
                    router.push('/register-profile');
                } else {
                    // 老用户直接进入首页
                    console.log('登录成功');
                    router.push('/home');
                }
            }
        }).catch((err) => {
            console.log(err);
        })
          
     }
}

更严谨的扩展方案(结合Firestore)

若担心短时间内重复登录导致时间判断失效,可在Firestore中为用户添加isRegistered标记:

  1. 新用户完善资料后,在Firestore的users集合中写入{ isRegistered: true }
  2. 验证OTP后先查询该标记,再决定跳转逻辑:
import { doc, getDoc } from "firebase/firestore";
import { db } from './firebase-config'; // 你的Firestore配置文件

const verifyOTP = async (e) => {
     let otp = e.target.value;
     setOtp(otp);
     if(otp.length === 6) {
        let confirmationResult = window.confirmationResult;
        try {
            const result = await confirmationResult.confirm(otp);
            const user = result.user;
            if(user) {
                // 查询用户是否已完成注册
                const userDocRef = doc(db, 'users', user.uid);
                const userDoc = await getDoc(userDocRef);
                
                if(userDoc.exists() && userDoc.data().isRegistered) {
                    router.push('/home');
                } else {
                    router.push('/register-profile');
                }
            }
        } catch(err) {
            console.log(err);
        }
     }
}

方案二:发送OTP前检查手机号是否已注册(需Cloud Function)

若希望在发送OTP前就拦截未注册用户,可借助Firebase云函数实现(前端无法直接查询手机号对应的用户):

步骤1:编写Cloud Function

在Firebase项目中创建Callable函数:

const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();

exports.checkPhoneExists = functions.https.onCall(async (data, context) => {
    const phoneNumber = data.phoneNumber;
    try {
        await admin.auth().getUserByPhoneNumber(phoneNumber);
        return { exists: true };
    } catch (error) {
        if (error.code === 'auth/user-not-found') {
            return { exists: false };
        }
        throw new functions.https.HttpsError('unknown', error.message);
    }
});

步骤2:前端调用云函数修改handleSubmit

发送OTP前先调用云函数检查手机号状态:

import { getFunctions, httpsCallable } from "firebase/functions";
const functions = getFunctions();

const handleSubmit = async (event) => {
    event.preventDefault();

    if(phone) {
        // 先检查手机号是否已注册
        const checkPhoneExists = httpsCallable(functions, 'checkPhoneExists');
        try {
            const result = await checkPhoneExists({ phoneNumber: phone });
            if(result.data.exists) {
                // 已注册用户,发送OTP
                setExpanded(true);
                generateRecaptcha();
                let appVerifier = window.recaptchaVerifier; // 注意修正原代码中的拼写错误(recapture→recaptcha)
                const confirmationResult = await signInWithPhoneNumber(auth, phone, appVerifier);
                window.confirmationResult = confirmationResult;
            } else {
                // 未注册用户,引导至注册页面
                console.log('该手机号未注册,请先完成注册');
                router.push('/register');
            }
        } catch(err) {
            console.log(err);
        }
    }
}

注意:原代码中window.recaptureVerifier存在拼写错误,正确应为window.recaptchaVerifier,请及时修正避免报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 07:40:39