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

能否通过Firebase Authentication向指定手机号发送含一次性令牌的短信?

能否通过Firebase Authentication向指定手机号发送一次性令牌短信?

可以实现,但Firebase Authentication原生的短信验证机制是针对用户自身手机号的认证流程设计的,无法直接给指定的第三方手机号发送一次性验证令牌。不过结合Firebase的Cloud Functions、Firestore,再搭配第三方短信服务,就能实现你需要的会员-管理员令牌验证流程。

具体实现方案

1. 准备Firestore数据结构

创建一个tokenVerifications集合,用于存储令牌的相关信息,每个文档包含以下字段:

  • token: 6位随机一次性数字令牌
  • adminPhone: 接收短信的管理员手机号
  • memberUid: 发起请求的会员UID
  • expiresAt: 令牌过期时间(建议设为15分钟,避免长期有效)
  • isUsed: 布尔值,标记令牌是否已被使用

2. 会员端触发请求

会员点击按钮后,调用后端Cloud Function发起令牌请求(避免前端直接操作敏感逻辑):

// 会员前端代码
async function requestAdminVerificationToken() {
  // 从Firestore管理员配置中拉取手机号,避免前端硬编码或篡改
  const adminConfigSnap = await firebase.firestore().collection('config').doc('admin').get();
  const adminPhone = adminConfigSnap.data().phone;

  try {
    const idToken = await firebase.auth().currentUser.getIdToken();
    const response = await fetch('/api/send-admin-token', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${idToken}`
      },
      body: JSON.stringify({ adminPhone })
    });

    const result = await response.json();
    result.success ? alert('已向管理员发送验证令牌,请等待告知') : alert('发送失败,请重试');
  } catch (err) {
    console.error('请求失败:', err);
    alert('请求出错,请稍后再试');
  }
}

3. Cloud Function生成令牌并发送短信

在Cloud Function中完成身份验证、令牌生成、存储及短信发送:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const twilio = require('twilio'); // 以Twilio为例,需提前配置账号

admin.initializeApp();
const twilioClient = twilio('你的Twilio Account SID', '你的Twilio Auth Token');

exports.sendAdminToken = functions.https.onRequest(async (req, res) => {
  // 验证会员身份
  const idToken = req.headers.authorization?.split('Bearer ')[1];
  if (!idToken) return res.status(401).json({ success: false, message: '未授权' });

  try {
    const decodedToken = await admin.auth().verifyIdToken(idToken);
    const memberUid = decodedToken.uid;
    const { adminPhone } = req.body;

    // 生成6位随机令牌
    const token = Math.floor(100000 + Math.random() * 900000).toString();
    // 设置15分钟过期时间
    const expiresAt = admin.firestore.Timestamp.fromDate(new Date(Date.now() + 15 * 60 * 1000));

    // 将令牌信息存入Firestore
    await admin.firestore().collection('tokenVerifications').add({
      token,
      adminPhone,
      memberUid,
      expiresAt,
      isUsed: false
    });

    // 给管理员发送短信
    await twilioClient.messages.create({
      body: `会员请求验证,一次性令牌:${token}(15分钟内有效)`,
      from: '你的Twilio手机号',
      to: adminPhone
    });

    res.status(200).json({ success: true });
  } catch (err) {
    functions.logger.error('发送令牌失败:', err);
    res.status(500).json({ success: false, message: err.message });
  }
});

4. 会员提交令牌并验证

会员拿到管理员告知的令牌后,提交表单并调用验证接口:

// 会员前端提交令牌代码
async function submitVerificationToken(tokenInput) {
  try {
    const idToken = await firebase.auth().currentUser.getIdToken();
    const response = await fetch('/api/verify-token', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${idToken}`
      },
      body: JSON.stringify({ token: tokenInput })
    });

    const result = await response.json();
    if (result.success) {
      alert('令牌验证成功');
      // 执行后续业务逻辑,比如提交表单、升级权限等
    } else {
      alert('令牌无效或已过期');
    }
  } catch (err) {
    console.error('验证失败:', err);
    alert('验证出错,请稍后再试');
  }
}

5. Cloud Function验证令牌有效性

编写验证令牌的Cloud Function,检查令牌的有效性、过期状态及使用状态:

exports.verifyToken = functions.https.onRequest(async (req, res) => {
  const idToken = req.headers.authorization?.split('Bearer ')[1];
  if (!idToken) return res.status(401).json({ success: false, message: '未授权' });

  try {
    const decodedToken = await admin.auth().verifyIdToken(idToken);
    const memberUid = decodedToken.uid;
    const { token } = req.body;

    // 查询符合条件的令牌:未使用、未过期、属于当前会员
    const querySnap = await admin.firestore()
      .collection('tokenVerifications')
      .where('token', '==', token)
      .where('memberUid', '==', memberUid)
      .where('isUsed', '==', false)
      .where('expiresAt', '>', admin.firestore.Timestamp.now())
      .get();

    if (querySnap.empty) {
      return res.status(400).json({ success: false, message: '令牌无效或已过期' });
    }

    // 标记令牌为已使用,避免重复验证
    await querySnap.docs[0].ref.update({ isUsed: true });

    res.status(200).json({ success: true });
  } catch (err) {
    functions.logger.error('验证令牌失败:', err);
    res.status(500).json({ success: false, message: err.message });
  }
});

关键注意事项

  • 安全性:管理员手机号从后端/数据库拉取,禁止前端直接传递;必须通过Firebase Auth的ID Token验证会员身份,确保请求来自合法用户。
  • 令牌生命周期:严格设置过期时间,并标记已使用的令牌,防止重复利用。
  • 短信服务:Firebase Auth不支持向非认证用户发送短信,需依赖第三方短信服务(如Twilio、Plivo等)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 00:50:31