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

Firebase Cloud Functions调用未授权问题排查咨询

问题:Firebase Cloud Functions调用未授权错误排查与解决

我通过Google和Apple登录实现用户登录功能,Firebase Authentication验证功能正常——控制台能看到已认证用户,也能通过以下代码获取用户token:

guard let user = Auth.auth().currentUser else {
    print("No authenticated user found.")
    return
}
user.getIDTokenResult { tok, error in
    print(tok?.token)
}

但调用Firebase Cloud Functions时却收到未授权错误,调用代码如下:

Functions.functions().httpsCallable("handleUserLogin").call(["uid": "uid", "email": "email"]) { (result, error) in
    print(error)
    print(result)
}

我尝试用cURL调用该函数,同样出现错误。

已执行的调试步骤

  • 未启用App Check
  • Firebase安全规则设置为完全开放(allow read, write: if true;)
  • 已确认token已生成且存在

Cloud Functions服务端代码

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

admin.initializeApp();

exports.handleUserLogin = functions.https.onCall(async (data, context) => {
    try {
        console.log("Authentication context:", context.auth);

        if (!context.auth) {
            console.error("Unauthenticated request");
            throw new functions.https.HttpsError(
                "unauthenticated",
                "The user must be authenticated to access this function."
            );
        }

        console.log("Authenticated user UID:", context.auth.uid);
        // Debug: Test Firestore write
        const testRef = admin.firestore().collection("test").doc("testDoc");
        try {
            await testRef.set({ test: "testValue" });
            console.log("Firestore test write successful.");
        } catch (error) {
            console.error("Firestore test write failed:", error);
        }

        // Process user login
        const { uid, email } = data;

        if (!uid || !email) {
            console.error("Invalid arguments: UID or Email missing");
            throw new functions.https.HttpsError(
                "invalid-argument",
                "UID and Email are required."
            );
        }

        const userRef = admin.firestore().collection("users").doc(uid);

        try {
            const doc = await userRef.get();

            if (doc.exists) {
                console.log("User exists:", doc.data());
                return { profile: doc.data(), newUser: false };
            } else {
                const newUser = {
                    email,
                    createdAt: admin.firestore.FieldValue.serverTimestamp(),
                };
                console.log("Creating new user profile:", newUser);

                await userRef.set(newUser);
                console.log("New user created successfully.");

                return { profile: newUser, newUser: true };
            }
        } catch (firestoreError) {
            console.error("Firestore operation failed:", firestoreError);
            throw new functions.https.HttpsError("internal", "Firestore operation failed.");
        }
    } catch (error) {
        console.error("Error handling user login:", error);
        throw new functions.https.HttpsError("internal", error.message || "An unexpected error occurred.");
    }
});

观察结果

函数中的context.auth对象为undefined,说明调用函数时用户未完成身份验证;安全规则完全开放,可排除规则问题。

核心问题

为什么调用该Cloud Functions时会收到未授权错误?如何确保调用函数时用户已正确完成身份验证?


原因分析与解决方法

1. 客户端调用时机或传参错误

httpsCallable默认会自动携带当前Auth用户的ID Token,但如果刚登录就立即调用函数,Auth状态可能还未同步到本地;或者你硬编码了"uid"和"email"的占位值,而非从真实用户对象获取。

解决方法:

  • 监听Auth状态变化,确认用户登录稳定后再调用函数:
Auth.auth().addStateDidChangeListener { auth, user in
    guard let user = user else { return }
    // 从当前用户获取真实的UID和邮箱
    Functions.functions().httpsCallable("handleUserLogin").call(["uid": user.uid, "email": user.email]) { result, error in
        print(error ?? "无错误")
        print(result?.data ?? "无结果")
    }
}

2. cURL调用未手动携带ID Token

cURL调用https.onCall函数不会自动携带认证信息,必须手动在请求头中添加Token。

正确的cURL示例:

curl -X POST https://<REGION>-<PROJECT_ID>.cloudfunctions.net/handleUserLogin \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <YOUR_ID_TOKEN>" \
  -d '{"uid": "用户真实UID", "email": "用户邮箱"}'

3. 客户端Firebase初始化异常

如果客户端Firebase App初始化不正确,会导致Auth信息无法传递到Functions。

解决方法:

  • 确认GoogleService-Info.plist已正确添加到项目中;
  • 确保先初始化Firebase,再创建Functions实例:
FirebaseApp.configure()
let functions = Functions.functions()

4. 函数部署版本问题

如果修改了认证逻辑但未重新部署,或者部署过程出错,旧代码可能仍在运行。

解决方法:

  • 重新部署目标函数:
firebase deploy --only functions:handleUserLogin
  • 到Cloud Functions控制台查看日志,确认运行的是最新代码版本。

额外优化建议

服务端可直接从context.auth获取用户信息,无需客户端传递,避免伪造参数:

// 替换原有的const { uid, email } = data;
const uid = context.auth.uid;
const email = context.auth.token.email; // 需确保用户邮箱已验证或存在

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 10:42:39