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

基于Firebase与React JS实现手机号+OTP注册及密码登录方案咨询

实现方案概述

Firebase Auth原生不支持手机号+密码直接登录,我们可以通过手机号OTP完成身份认证 + Firestore存储加密后的用户密码的组合方式实现需求:

  1. 注册阶段:用户输入手机号→获取并验证OTP→验证通过后设置密码→将加密后的密码与用户UID关联存储到Firestore
  2. 登录阶段:用户输入手机号+密码→从Firestore获取对应手机号的加密密码→比对密码正确性→验证通过后用手机号OTP完成登录(符合Firebase Auth安全规范)

一、Firebase 后端配置

  1. 启用Firebase Auth的手机号认证:在Firebase控制台→Authentication→登录方法中开启手机号登录
  2. 创建Firestore数据库:用于存储用户的手机号、加密密码和关联UID,需设置安全规则确保数据访问权限

二、前端React实现步骤

1. 初始化Firebase

安装依赖:

npm install firebase bcryptjs

(bcryptjs用于密码哈希加密,禁止明文存储)

创建Firebase配置文件:

// firebaseConfig.js
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";

const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_AUTH_DOMAIN",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_STORAGE_BUCKET",
  messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
  appId: "YOUR_APP_ID"
};

const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const db = getFirestore(app);

2. 注册组件(OTP验证+密码设置)

import { useState } from "react";
import { auth, db } from "./firebaseConfig";
import { signInWithPhoneNumber, RecaptchaVerifier } from "firebase/auth";
import { doc, setDoc } from "firebase/firestore";
import bcrypt from "bcryptjs";

const Register = () => {
  const [phoneNumber, setPhoneNumber] = useState("");
  const [otp, setOtp] = useState("");
  const [password, setPassword] = useState("");
  const [confirmationResult, setConfirmationResult] = useState(null);

  // 初始化reCAPTCHA验证器(Firebase手机号认证强制要求)
  const setupRecaptcha = () => {
    window.recaptchaVerifier = new RecaptchaVerifier(
      "recaptcha-container",
      { size: "invisible" },
      auth
    );
  };

  // 发送OTP验证码
  const handleSendOtp = async () => {
    setupRecaptcha();
    try {
      const appVerifier = window.recaptchaVerifier;
      const response = await signInWithPhoneNumber(auth, phoneNumber, appVerifier);
      setConfirmationResult(response);
      alert("OTP已发送至您的手机号");
    } catch (error) {
      console.error("发送OTP失败:", error);
      alert("发送失败,请检查手机号格式并重试");
    }
  };

  // 验证OTP并完成注册
  const handleVerifyAndRegister = async () => {
    if (!confirmationResult) return;
    try {
      // 验证OTP,完成Firebase手机号认证
      const userCredential = await confirmationResult.confirm(otp);
      const user = userCredential.user;

      // 哈希加密密码
      const hashedPassword = await bcrypt.hash(password, 10);

      // 将用户信息存储到Firestore
      await setDoc(doc(db, "users", user.uid), {
        phoneNumber: phoneNumber,
        hashedPassword: hashedPassword,
        uid: user.uid
      });

      alert("注册成功!");
      // 此处可跳转至首页或登录页
    } catch (error) {
      console.error("注册失败:", error);
      alert("验证失败,请检查验证码或密码格式");
    }
  };

  return (
    <div className="register-box">
      <h2>用户注册</h2>
      <div id="recaptcha-container"></div>
      <input
        type="tel"
        placeholder="请输入手机号(格式:+86138xxxx1234)"
        value={phoneNumber}
        onChange={(e) => setPhoneNumber(e.target.value)}
      />
      <button onClick={handleSendOtp}>发送验证码</button>

      {confirmationResult && (
        <>
          <input
            type="text"
            placeholder="请输入6位验证码"
            value={otp}
            onChange={(e) => setOtp(e.target.value)}
          />
          <input
            type="password"
            placeholder="设置登录密码"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
          <button onClick={handleVerifyAndRegister}>完成注册</button>
        </>
      )}
    </div>
  );
};

export default Register;

3. 登录组件(手机号+密码验证)

import { useState } from "react";
import { auth, db } from "./firebaseConfig";
import { signInWithPhoneNumber, RecaptchaVerifier } from "firebase/auth";
import { collection, query, where, getDocs } from "firebase/firestore";
import bcrypt from "bcryptjs";

const Login = () => {
  const [phoneNumber, setPhoneNumber] = useState("");
  const [password, setPassword] = useState("");

  // 初始化登录用reCAPTCHA
  const setupRecaptcha = () => {
    window.recaptchaVerifier = new RecaptchaVerifier(
      "login-recaptcha",
      { size: "invisible" },
      auth
    );
  };

  const handleLogin = async () => {
    try {
      // 从Firestore查询该手机号的用户数据
      const userQuery = query(collection(db, "users"), where("phoneNumber", "==", phoneNumber));
      const querySnapshot = await getDocs(userQuery);

      if (querySnapshot.empty) {
        alert("该手机号未注册");
        return;
      }

      const userData = querySnapshot.docs[0].data();
      // 比对密码哈希值
      const isPasswordValid = await bcrypt.compare(password, userData.hashedPassword);
      if (!isPasswordValid) {
        alert("密码错误");
        return;
      }

      // 密码验证通过,发送OTP完成Firebase登录
      setupRecaptcha();
      const appVerifier = window.recaptchaVerifier;
      const response = await signInWithPhoneNumber(auth, phoneNumber, appVerifier);
      const otp = prompt("请输入登录验证码");
      if (!otp) return;
      await response.confirm(otp);
      alert("登录成功!");
      // 跳转至首页
    } catch (error) {
      console.error("登录失败:", error);
      alert("登录失败,请检查账号密码或重试");
    }
  };

  return (
    <div className="login-box">
      <h2>用户登录</h2>
      <div id="login-recaptcha"></div>
      <input
        type="tel"
        placeholder="请输入手机号"
        value={phoneNumber}
        onChange={(e) => setPhoneNumber(e.target.value)}
      />
      <input
        type="password"
        placeholder="请输入登录密码"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <button onClick={handleLogin}>登录</button>
    </div>
  );
};

export default Login;

三、安全注意事项

  1. 密码存储:必须使用bcrypt等哈希算法加密,禁止明文存储密码
  2. Firestore安全规则:设置规则限制数据访问权限,示例规则:
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{uid} {
      allow read, write: if request.auth != null && request.auth.uid == uid;
    }
  }
}
  1. reCAPTCHA验证:必须启用,防止机器人恶意攻击
  2. 密码重置:可通过手机号OTP验证身份后,更新Firestore中的哈希密码

内容的提问来源于stack exchange,提问作者Adarsh Kumar Maurya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 17:10:16