如何获取运行Google Cloud Function的服务账号访问令牌以调用GCP API?
解决Cloud Function调用App Engine Admin API的401未授权问题
你遇到的问题是因为直接调用App Engine Admin API时,请求没有携带Cloud Function运行时服务账号的授权凭证,需要显式获取访问令牌并添加到请求头中。下面提供两种可行的解决方案:
方法一:使用Google官方Auth库(推荐)
借助google-auth-library可以自动处理令牌的获取、刷新,是最规范的实现方式:
- 先在Cloud Function的项目目录安装依赖:
npm install google-auth-library
- 修改你的函数代码如下:
const {GoogleAuth} = require('google-auth-library'); const functions = require('firebase-functions'); // 或对应的Cloud Functions官方库 functions.http('toggleFingerprintServer', async (req, res) => { // 初始化Auth客户端,默认使用当前Cloud Function运行的服务账号 const auth = new GoogleAuth({ scopes: ['https://www.googleapis.com/auth/appengine.admin'] }); const client = await auth.getClient(); // 获取访问令牌 const accessToken = await client.getAccessToken(); if (!req.query || !req.query.servingStatus || (req.query.servingStatus!== 'SERVING' && req.query.servingStatus!== 'STOPPED')) { return res.status(400).json({status: 400, message: "Status must be SERVING or STOPPED"}); } const externalRes = await fetch('https://content-appengine.googleapis.com/v1/apps/demoApp/services/fingerprint-api/versions/1?updateMask=servingStatus', { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken.token}` }, body: JSON.stringify({servingStatus: req.query.servingStatus}), }); res.sendStatus(externalRes.ok ? 200 : 500); });
方法二:直接调用元数据服务器获取令牌(无依赖)
如果不想引入额外依赖,可以直接调用GCP的元数据服务器获取当前服务账号的令牌:
const functions = require('firebase-functions'); // 或对应的Cloud Functions官方库 functions.http('toggleFingerprintServer', async (req, res) => { // 从元数据服务器获取访问令牌 const tokenRes = await fetch('http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token?scopes=https://www.googleapis.com/auth/appengine.admin', { headers: {'Metadata-Flavor': 'Google'} }); const tokenData = await tokenRes.json(); const accessToken = tokenData.access_token; if (!req.query || !req.query.servingStatus || (req.query.servingStatus!== 'SERVING' && req.query.servingStatus!== 'STOPPED')) { return res.status(400).json({status: 400, message: "Status must be SERVING or STOPPED"}); } const externalRes = await fetch('https://content-appengine.googleapis.com/v1/apps/demoApp/services/fingerprint-api/versions/1?updateMask=servingStatus', { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}` }, body: JSON.stringify({servingStatus: req.query.servingStatus}), }); res.sendStatus(externalRes.ok ? 200 : 500); });
额外检查项
- 确认你的Cloud Function服务账号已被授予
App Engine Admin角色(或包含appengine.services.update权限的自定义角色) - 确保API请求中的
demoApp是你的实际GCP项目ID(App Engine应用ID和项目ID一致)
内容的提问来源于stack exchange,提问作者Oirampok
相关产品推荐
相关产品推荐

