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

Flutter Firebase迁移Cloud Functions V2后Razorpay支付ID创建失败

Flutter Firebase迁移Cloud Functions V2后Razorpay支付ID创建失败(报错"User must be authenticated")

问题概述

  • 背景:Flutter Firebase应用集成Razorpay支付网关已1年,近期删除V1云函数并迁移至Cloud Functions V2
  • 症状:调用支付ID创建API返回空响应,核心报错为User must be authenticated
  • 已执行排查:
    • 在云函数关键位置添加调试语句
    • 确认main.dart中已完成Firebase初始化

错误日志示例

Error: User must be authenticated
    at createPaymentId (/workspace/index.js:22:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async onRequest (/workspace/index.js:35:9)

相关代码片段

Cloud Functions V2 支付函数代码

import { onRequest } from "firebase-functions/v2/https";
import * as admin from "firebase-admin";

admin.initializeApp();

export const createPaymentId = onRequest(async (req, res) => {
  // 调试输出
  console.log("Request headers:", req.headers);
  console.log("Request auth state:", req.auth);

  if (!req.auth) {
    return res.status(401).json({ error: "User must be authenticated" });
  }

  // Razorpay 订单创建逻辑(原V1逻辑)
  // ...
  res.json({ paymentId: "generated_payment_id" });
});

Flutter端API调用代码

final response = await http.post(
  Uri.parse("https://us-central1-your-project-id.cloudfunctions.net/createPaymentId"),
  headers: {
    "Content-Type": "application/json",
    // 疑似ID Token传递存在问题
    // "Authorization": "Bearer ${FirebaseAuth.instance.currentUser?.getIdToken()}"
  },
  body: jsonEncode({
    "amount": 1000,
    "currency": "INR"
  }),
);

print("Response status: ${response.statusCode}");
print("Response body: ${response.body}");

排查与解决方案

1. 修正Cloud Functions V2的身份验证逻辑

Cloud Functions V2的onRequest函数不会自动解析Firebase Auth的ID Token(与V1行为不同),需手动验证:

// 更新后的云函数验证逻辑
export const createPaymentId = onRequest(async (req, res) => {
  // 从请求头获取ID Token
  const idToken = req.headers.authorization?.split("Bearer ")[1];
  if (!idToken) {
    return res.status(401).json({ error: "User must be authenticated" });
  }

  try {
    // 验证并解码ID Token
    const decodedToken = await admin.auth().verifyIdToken(idToken);
    // 可将用户信息存入req供后续逻辑使用
    req.user = decodedToken;
  } catch (error) {
    return res.status(401).json({ error: "Invalid or expired token" });
  }

  // Razorpay订单创建逻辑
  // ...
  res.json({ paymentId: "generated_payment_id" });
});

或改用onCall函数(Firebase自动处理身份验证):

import { onCall } from "firebase-functions/v2/https";

export const createPaymentId = onCall(async (request) => {
  if (!request.auth) {
    throw new functions.https.HttpsError(
      "unauthenticated",
      "User must be authenticated"
    );
  }

  // Razorpay订单创建逻辑
  // ...
  return { paymentId: "generated_payment_id" };
});

2. 确保Flutter端正确传递ID Token

需异步获取有效ID Token并添加至请求头:

// 修正后的Flutter调用代码
final user = FirebaseAuth.instance.currentUser;
if (user == null) {
  // 处理未登录状态
  return;
}

final idToken = await user.getIdToken();
final response = await http.post(
  Uri.parse("https://us-central1-your-project-id.cloudfunctions.net/createPaymentId"),
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer $idToken",
  },
  body: jsonEncode({
    "amount": 1000,
    "currency": "INR"
  }),
);

3. 检查云函数IAM权限

进入Firebase控制台 → Cloud Functions → 选择createPaymentId函数 → 权限:

  • 添加成员allAuthenticatedUsers
  • 授予Cloud Functions Invoker角色

4. 查看完整调试日志

在Firebase控制台的云函数日志中,检查:

  • 请求头是否包含Authorization字段
  • ID Token验证环节的报错信息(如过期、无效等)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 12:07:15