如何从OnCall云函数调用带Firebase Token的另一个OnCall函数?
问题描述
我需要保护我的Cloud Functions,不清楚如何在从一个函数调用另一个函数时传递正确的Firebase Token,也不知道如何生成有效的idToken。我提供了两个OnCall云函数(Prova和Prova2)的代码示例,客户端通过FirebaseFunction.instance.httpCallable()调用这些函数。
Prova函数代码:
const { logger, HttpsError } = require("firebase-functions/v2"); const { initializeApp } = require("firebase-admin/app"); const { onCall } = require("firebase-functions/v2/https"); initializeApp(); exports.Prova = onCall(async (data) => { try { // 检查用户是否已认证 if (!data.auth) { throw new HttpsError("unauthenticated", "用户未认证"); } const idToken = ?? const callResponse = await fetch('https://us-central1-NAME_PROJECT.cloudfunctions.net/Prova2', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${idToken}` }, body: JSON.stringify({ "data": {} }) }); return { success: true, message: "操作成功" }; } catch (error) { logger.error("错误:", error.message); return { success: false, message: "内部错误", details: error.message }; } });
Prova2函数代码:
const { logger } = require("firebase-functions/v2"); const { initializeApp } = require("firebase-admin/app"); const { onCall } = require("firebase-functions/v2/https"); initializeApp(); exports.Prova2 = onCall(async (data) => { // 检查用户是否已认证 if (!data.auth) { throw new HttpsError('unauthenticated', '用户未认证'); } try { return{ message: '操作成功' }; } catch (error) { logger.error(error.message); return{ message: '操作失败' }; } });
解决方案
1. 修正云函数的认证参数获取
Firebase V2的onCall函数接收的参数是context对象,用户的认证信息在context.auth中,而非data.auth。你的代码错误地将context当作data处理,这会导致认证检查失效,需先修正这一点。
2. 生成有效的ID Token
在云函数中,可通过Firebase Admin SDK的auth().createIdToken(uid)方法,为当前认证用户生成有效的ID Token,该Token可用于调用其他需要用户身份的OnCall函数。
3. 正确调用另一个云函数
调用时需在请求头中携带生成的ID Token,并严格按照OnCall函数的请求格式传递数据。
修正后的完整代码
Prova函数(调用方)
const { logger, HttpsError } = require("firebase-functions/v2"); const { initializeApp } = require("firebase-admin/app"); const { getAuth } = require("firebase-admin/auth"); const { onCall } = require("firebase-functions/v2/https"); initializeApp(); const auth = getAuth(); exports.Prova = onCall(async (context) => { try { // 检查用户是否已认证 if (!context.auth) { throw new HttpsError("unauthenticated", "用户未认证"); } // 获取当前用户UID并生成ID Token const uid = context.auth.uid; const idToken = await auth.createIdToken(uid); // 调用Prova2函数 const callResponse = await fetch('https://us-central1-NAME_PROJECT.cloudfunctions.net/Prova2', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${idToken}` }, body: JSON.stringify({ "data": {} // 此处可传递给Prova2的业务参数 }) }); // 解析Prova2的响应 const responseData = await callResponse.json(); if (!callResponse.ok) { throw new HttpsError(responseData.error.code, responseData.error.message); } return { success: true, message: "操作成功", prova2Response: responseData }; } catch (error) { logger.error("错误:", error.message); return { success: false, message: "内部错误", details: error.message }; } });
Prova2函数(被调用方)
const { logger, HttpsError } = require("firebase-functions/v2"); const { initializeApp } = require("firebase-admin/app"); const { onCall } = require("firebase-functions/v2/https"); initializeApp(); exports.Prova2 = onCall(async (context) => { // 检查用户是否已认证 if (!context.auth) { throw new HttpsError('unauthenticated', '用户未认证'); } try { // 获取当前用户UID,执行业务逻辑 const uid = context.auth.uid; logger.info(`用户 ${uid} 调用了Prova2函数`); return { message: '操作成功', userId: uid }; } catch (error) { logger.error(error.message); throw new HttpsError('internal', '内部错误', error.message); } });
关键说明
- Admin SDK权限:云函数中初始化的Admin SDK拥有最高权限,用
createIdToken生成的Token与客户端登录后获取的Token效力一致,可正常通过OnCall函数的认证检查。 - 请求格式:调用OnCall函数时,必须将参数放在
data字段中,请求头需包含Content-Type: application/json和携带Token的Authorization头。 - 错误处理:调用后需检查响应状态,解析错误信息并抛出标准的
HttpsError,确保客户端能正确接收错误提示。
内容的提问来源于stack exchange,提问作者Luciano d'Agostino
相关产品推荐
相关产品推荐

