You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React Expo移动端应用Firebase手机号认证及OTP接口开发问题求助

React Expo移动端应用Firebase手机号认证及OTP接口开发问题求助

嘿,看你在开发React Expo移动端的手机号OTP认证功能,还写了Express后端接口但代码没写完对吧?我来帮你补全代码、梳理开发流程,再结合Firebase的手机号认证给你一些实用建议~

首先先把你没写完的后端Express OTP接口补全并优化下,这块是用户获取和验证验证码的核心:

import { Router, Request, Response } from 'express';
import { deleteOtp, generateOtp, verifyOtp } from '../services/otp.services';
import { sendOtp } from '../utils/sendOtp';

const router = Router();

// 发送OTP验证码接口
router.post('/send-otp', async (req: Request, res: Response) => {
    try {
        const { phone } = req.body;
        // 先校验手机号是否传入
        if (!phone) return res.status(400).json({ message: '手机号为必填项,请检查输入' });

        // 生成OTP并存储(建议用Redis带过期时间,或者数据库加过期字段,比如5分钟过期)
        const otp = await generateOtp(phone);
        // 调用短信服务发送OTP到用户手机
        await sendOtp(phone, otp);

        res.status(200).json({ message: '验证码已发送,请注意查收短信' });
    } catch (error) {
        console.error('发送验证码出错:', error);
        res.status(500).json({ message: '发送验证码失败,请稍后重试' });
    }
});

// 验证OTP验证码接口
router.post('/verify-otp', async (req: Request, res: Response) => {
    try {
        const { phone, otp } = req.body;
        // 校验必填参数
        if (!phone || !otp) return res.status(400).json({ message: '手机号和验证码均为必填项' });

        // 验证OTP是否有效(检查是否存在、是否过期)
        const isVerified = await verifyOtp(phone, otp);
        if (!isVerified) return res.status(401).json({ message: '验证码无效或已过期,请重新获取' });

        // 验证成功后删除已使用的OTP,防止重复验证
        await deleteOtp(phone);

        // 这里可以结合Firebase Admin SDK生成自定义登录token,返回给Expo端用于Firebase认证
        // 如果你用Firebase原生的手机号认证,这步也可以省略,直接让Expo端和Firebase交互
        // const customToken = await admin.auth().createCustomToken(phone);
        res.status(200).json({ 
            message: '验证码验证成功',
            // customToken: customToken // 需要的话就返回这个
        });
    } catch (error) {
        console.error('验证验证码出错:', error);
        res.status(500).json({ message: '验证验证码失败,请稍后重试' });
    }
});

export default router;

接下来是Expo移动端的代码,结合Firebase的手机号认证,给你结合后端接口的实现示例:

  1. 先在Expo项目里安装Firebase依赖:
npx expo install firebase
  1. 配置Firebase(从Firebase控制台复制你的项目配置):
// src/firebaseConfig.js
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';

const firebaseConfig = {
  apiKey: "你的API_KEY",
  authDomain: "你的AUTH_DOMAIN",
  projectId: "你的PROJECT_ID",
  storageBucket: "你的STORAGE_BUCKET",
  messagingSenderId: "你的MESSAGING_SENDER_ID",
  appId: "你的APP_ID"
};

const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
  1. 编写手机号认证的页面组件:
import { useState } from 'react';
import { View, TextInput, Button, Alert, StyleSheet } from 'react-native';
import { auth } from '../firebaseConfig';
import { signInWithCustomToken } from 'firebase/auth';

const PhoneAuthScreen = () => {
  const [phone, setPhone] = useState('');
  const [otp, setOtp] = useState('');

  // 调用后端接口发送验证码
  const handleSendOtp = async () => {
    if (!phone.trim()) {
      Alert.alert('提示', '请输入手机号');
      return;
    }
    try {
      const response = await fetch('https://你的后端域名/send-otp', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ phone: `+86${phone}` }), // 统一格式为带国际区号的手机号
      });
      const data = await response.json();
      if (response.ok) {
        Alert.alert('成功', data.message);
      } else {
        Alert.alert('错误', data.message);
      }
    } catch (err) {
      Alert.alert('错误', '发送验证码失败,请检查网络后重试');
    }
  };

  // 验证验证码并完成Firebase登录
  const handleVerifyOtp = async () => {
    if (!phone.trim() || !otp.trim()) {
      Alert.alert('提示', '请填写手机号和验证码');
      return;
    }
    try {
      const response = await fetch('https://你的后端域名/verify-otp', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ phone: `+86${phone}`, otp }),
      });
      const data = await response.json();
      if (response.ok) {
        // 如果后端返回了Firebase自定义token,用这个完成登录
        if (data.customToken) {
          await signInWithCustomToken(auth, data.customToken);
          Alert.alert('成功', '手机号认证完成!');
          // 这里可以跳转到首页或者其他页面
        } else {
          Alert.alert('成功', '验证码验证通过');
        }
      } else {
        Alert.alert('错误', data.message);
      }
    } catch (err) {
      Alert.alert('错误', '验证验证码失败,请检查网络后重试');
    }
  };

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        placeholder="请输入手机号(如138xxxx1234)"
        value={phone}
        onChangeText={setPhone}
        keyboardType="phone-pad"
        maxLength={11}
      />
      <Button title="发送验证码" onPress={handleSendOtp} />
      <TextInput
        style={styles.input}
        placeholder="请输入6位验证码"
        value={otp}
        onChangeText={setOtp}
        keyboardType="number-pad"
        maxLength={6}
      />
      <Button title="验证并登录" onPress={handleVerifyOtp} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    justifyContent: 'center',
    gap: 15,
  },
  input: {
    borderWidth: 1,
    borderColor: '#ccc',
    padding: 12,
    borderRadius: 8,
  },
});

export default PhoneAuthScreen;

最后给你几个踩坑提醒,都是我之前做这类功能遇到的:

  • 手机号格式一定要统一!不管是后端存储还是前端传入,都用带国际区号的格式(比如+86开头),避免不同格式导致验证失败
  • OTP的过期时间别设太长,5分钟左右刚好,存储的时候一定要加过期逻辑,防止旧验证码被重复使用
  • Expo端要确保网络权限正常,iOS和Android的配置里都要开启网络访问权限
  • 如果选择用Firebase原生的手机号认证,其实Firebase已经帮你处理了OTP的发送和验证,你可以直接用signInWithPhoneNumber方法,不用自己搭后端OTP服务,看你需求来选

内容来源于stack exchange

火山引擎 最新活动