英文:
Firebase Cloud Functions V2: The request was not authorized to invoke this service
问题
我正在尝试从客户端应用程序调用一个可调用的云函数(已部署),并在GCP日志中收到以下错误消息:
{
httpRequest: {9}
insertId: "647865c20002422d2d32b259"
labels: {1}
logName: "projects/faker-app-flutter-firebase-dev/logs/run.googleapis.com%2Frequests"
receiveTimestamp: "2023-06-01T09:32:50.154902339Z"
resource: {2}
severity: "WARNING"
spanId: "11982344486849947204"
textPayload: "The request was not authorized to invoke this service. Read more at https://cloud.google.com/run/docs/securing/authenticating Additional troubleshooting documentation can be found at: https://cloud.google.com/run/docs/troubleshooting#401"
timestamp: "2023-06-01T09:32:50.138090Z"
trace: "projects/faker-app-flutter-firebase-dev/traces/ddcb5a4df500af085b7a7f6f89a72ace"
traceSampled: true
}
相同的函数在Firebase本地模拟器中可以正常工作,因此我认为这是与IAM和服务帐户相关的权限问题(我仍然不太了解IAM的工作原理)。
以下是我的代码:
import * as admin from "firebase-admin";
import * as functions from "firebase-functions/v2";
import * as logger from "firebase-functions/logger";
// https://github.com/firebase/firebase-tools/issues/1532
if (admin.apps.length === 0) {
admin.initializeApp()
}
export const deleteAllUserJobs = functions.https.onCall(async (context: functions.https.CallableRequest) => {
const uid = context.auth?.uid
if (uid === undefined) {
throw new functions.https.HttpsError("unauthenticated", "You need to be authenticated to perform this action")
}
const firestore = admin.firestore()
const collectionRef = firestore.collection(`/users/${uid}/jobs`)
const collection = await collectionRef.get()
logger.debug(`Deleting ${collection.docs.length} docs at "/users/${uid}/jobs"`)
// transaction version
await firestore.runTransaction(async (transaction) => {
for (const doc of collection.docs) {
transaction.delete(firestore.doc(`/users/${uid}/jobs/${doc.id}`))
}
})
logger.debug(`Deleted ${collection.docs.length} docs at "/users/${uid}/jobs"`)
return {"success": true}
})
函数使用 firebase deploy --only functions
部署,并且我确保在用户已经获得授权的情况下客户端应用程序调用此函数。
根据文档:
如果在部署函数时遇到权限错误,请确保已将适当的IAM角色分配给运行部署命令的用户。
文档还链接到此页面,其中提到:
Firebase云函数权限
有关云函数权限的列表和描述,请参阅IAM文档。
请注意,部署函数需要一种特定的权限配置,这些权限不包含在标准Firebase预定义角色中。要部署函数,请使用以下选项之一:
将函数部署委托给项目所有者。 如果只部署非HTTP函数,则项目编辑可以部署您的函数。 将函数部署委托给具有以下两个角色的项目成员: 云函数管理员角色(roles/cloudfunctions.admin) 服务帐户用户角色(roles/iam.serviceAccountUser) 项目所有者可以使用Google Cloud控制台或gcloud CLI为项目成员分配这些角色。有关此角色配置的详细步骤和安全性说明,请参阅IAM文档。
但正如我所说,我可以成功部署函数。问题出现在我尝试执行它时才会得到错误日志。
总结一下,我正在尝试做的事情非常基本:
- 编写一个可调用的云函数
- 部署它
- 从客户端应用程序调用它
当函数运行时,它会出现上面的错误。是否需要设置特定的IAM角色?
英文:
I'm attempting to call a callable cloud function (which is already deployed) from a client app and getting this error on the GCP logs:
{
httpRequest: {9}
insertId: "647865c20002422d2d32b259"
labels: {1}
logName: "projects/faker-app-flutter-firebase-dev/logs/run.googleapis.com%2Frequests"
receiveTimestamp: "2023-06-01T09:32:50.154902339Z"
resource: {2}
severity: "WARNING"
spanId: "11982344486849947204"
textPayload: "The request was not authorized to invoke this service. Read more at https://cloud.google.com/run/docs/securing/authenticating Additional troubleshooting documentation can be found at: https://cloud.google.com/run/docs/troubleshooting#401"
timestamp: "2023-06-01T09:32:50.138090Z"
trace: "projects/faker-app-flutter-firebase-dev/traces/ddcb5a4df500af085b7a7f6f89a72ace"
traceSampled: true
}
The same function works correctly from the Firebase Local Emulator, so I assume this is a permissions issue related to IAM and service accounts (I still don't understand too well how IAM works).
Here is my code:
import * as admin from "firebase-admin"
import * as functions from "firebase-functions/v2"
import * as logger from "firebase-functions/logger";
// https://github.com/firebase/firebase-tools/issues/1532
if (admin.apps.length === 0) {
admin.initializeApp()
}
export const deleteAllUserJobs = functions.https.onCall(async (context: functions.https.CallableRequest) => {
const uid = context.auth?.uid
if (uid === undefined) {
throw new functions.https.HttpsError("unauthenticated", "You need to be authenticated to perform this action")
}
const firestore = admin.firestore()
const collectionRef = firestore.collection(`/users/${uid}/jobs`)
const collection = await collectionRef.get()
logger.debug(`Deleting ${collection.docs.length} docs at "/users/${uid}/jobs"`)
// transaction version
await firestore.runTransaction(async (transaction) => {
for (const doc of collection.docs) {
transaction.delete(firestore.doc(`/users/${uid}/jobs/${doc.id}`))
}
})
logger.debug(`Deleted ${collection.docs.length} docs at "/users/${uid}/jobs"`)
return {"success": true}
})
The function was deployed with firebase deploy --only functions
, and I made sure the client app calls this function when the user is already authorized.
According to the docs:
> If you encounter permissions errors when deploying functions, make sure that the appropriate IAM roles are assigned to the user running the deployment commands.
The docs also link to this page, which says:
> Cloud Functions for Firebase permissions
>
> For a list and descriptions of Cloud Functions permissions, refer to
> the IAM documentation.
>
> Be aware that the deployment of functions requires a specific
> configuration of permissions that aren't included in the standard
> Firebase predefined roles. To deploy functions, use one of the
> following options:
>
> Delegate the deployment of functions to a project Owner.
>
> If you're deploying only non-HTTP functions, then a project Editor can deploy your functions.
>
> Delegate deployment of functions to a project member who has the following two roles:
> Cloud Functions Admin role (roles/cloudfunctions.admin)
> Service Account User role (roles/iam.serviceAccountUser)
>
> A project Owner can assign these roles to a project member using the Google Cloud Console or gcloud CLI. For detailed steps and
> security implications for this role configuration, refer to the IAM
> documentation.
But like I said, I can successfully deploy the function. It's when I try to execute it that I get an error log.
In summary, what I'm trying to do is quite basic:
- write a callable cloud function
- deploy it
- call it from the client app
When the function runs, it fails with the error above.
Any advice? Do I need to set a specific IAM role?
答案1
得分: 2
打开 https://console.cloud.google.com/iam-admin/<project_name>
,找到您在 Firebase 项目中正在使用的服务帐户,并添加角色 "Cloud Functions Invoker"。
就像管理员、编辑员或查看器角色是关于在 GCP 上操作函数(不允许您使用它),而 Invoker 允许该帐户调用该函数。
英文:
Open https://console.cloud.google.com/iam-admin/<project_name>
, find the service account you are using in your firebase project and add the Rol "Cloud Functions Invoker".
Is like Admin, Editor or Viewer roles are about manipulating the function on GCP (don't allow you to use it) and Invoker allows that account to invoke the function.
答案2
得分: 2
经过多次尝试和错误,我成功地使其工作,方法是将"Cloud Functions Invoker"角色添加到firebase-service-account@firebase-sa-management.iam.gserviceaccount.com
主体的IAM和管理页面中。
英文:
After much trial and error, I managed to get it working by adding the "Cloud Functions Invoker" role to the firebase-service-account@firebase-sa-management.iam.gserviceaccount.com
principal in the IAM & Admin page:
答案3
得分: 0
你必须在控制台中下载 serviceAccountKey.json 文件。然后,你必须执行类似以下的操作:
const admin = require("firebase-admin");
const serviceAccount = require("./serviceAccountKey.json");
// 这里放入一些代码...
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
// 你的 API...
英文:
You must download serviceAccountKey.json in Console. Than, you must do something like this:
const admin = require("firebase-admin");
const serviceAccount = require("./serviceAccountKey.json");
// some code here...
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
// your api...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论