如何实现同项目Cloud Function调用App Engine的身份认证
好问题!既然你的Cloud Function和App Engine同属一个GCP项目,用服务账号的ID Token来做身份认证是完全可行的——这是最安全且省心的方案,不需要手动管理密钥,GCP会自动处理凭据的轮换。下面我一步步给你讲具体操作:
解决方案:使用服务账号ID Token实现跨服务认证
核心思路
Cloud Function利用自身运行环境默认挂载的服务账号凭据,生成一个针对App Engine目标资源的ID Token,将这个Token放在请求的Authorization头中;App Engine端验证Token的有效性(包括签名、受众、签发者等),验证通过后再处理业务请求。
步骤1:修改Cloud Function代码,生成并携带ID Token
首先,你需要在Cloud Function的依赖中添加google-auth库(直接写在requirements.txt里即可,部署时会自动安装),然后调整请求逻辑:
import json import urllib.request from google.oauth2 import id_token from google.auth.transport import requests def your_cloud_function_handler(event, context): # 目标App Engine资源的完整URL target_url = "https://project-name.appspot.com/urlidentifier" # 生成ID Token:受众必须设置为目标资源的URL try: id_token_str = id_token.fetch_id_token(requests.Request(), target_url) except Exception as e: print(f"生成ID Token失败: {str(e)}") return {"status": "error", "message": str(e)}, 500 # 准备JSON格式的请求数据 data_obj = {'sample': 'data'} data_json = json.dumps(data_obj).encode('utf-8') # 构建请求,添加Authorization头 req = urllib.request.Request( target_url, data=data_json, headers={ 'Content-Type': 'application/json', 'Authorization': f'Bearer {id_token_str}' } ) try: resp = urllib.request.urlopen(req) response_data = resp.read().decode('utf-8') return {"status": "success", "response": response_data}, 200 except urllib.error.HTTPError as e: return {"status": "error", "code": e.code, "message": e.read().decode('utf-8')}, e.code
关键细节:
id_token.fetch_id_token会自动读取Cloud Function运行环境中的默认服务账号凭据,完全不需要手动下载密钥文件。- 受众(Audience)必须严格设置为目标App Engine资源的完整URL,这是Token验证的核心依据。
- 把原来的
urlencode逻辑改成直接发送JSON数据,符合常规的API请求格式,也方便App Engine端解析。
步骤2:修改App Engine应用,验证ID Token
你的App Engine原本用Firebase用户认证,现在需要添加服务账号ID Token的验证逻辑。以下是Python 2.7的示例代码(假设你用的是Webapp2框架):
import webapp2 import json from google.auth import jwt from google.auth.transport import requests class UrlIdentifierHandler(webapp2.RequestHandler): def post(self): # 提取Authorization头中的Token auth_header = self.request.headers.get('Authorization') if not auth_header or not auth_header.startswith('Bearer '): self.response.status = 401 self.response.write(json.dumps({"error": "缺少有效认证信息"})) return id_token_str = auth_header.split(' ')[1] # 验证ID Token的有效性 try: claims = jwt.verify( id_token_str, requests.Request(), # 受众必须和Cloud Function中设置的完全一致 audience="https://project-name.appspot.com/urlidentifier", # 签发者固定为Google账号服务域名 issuer="https://accounts.google.com" ) # 可选:额外限制仅本项目服务账号可访问 if not claims['email'].endswith('@project-name.iam.gserviceaccount.com'): raise ValueError("非本项目服务账号发起的请求") except Exception as e: self.response.status = 403 self.response.write(json.dumps({"error": f"认证失败: {str(e)}"})) return # 验证通过,处理业务逻辑 request_data = json.loads(self.request.body) self.response.write(json.dumps({"status": "success", "received_data": request_data})) app = webapp2.WSGIApplication([ ('/urlidentifier', UrlIdentifierHandler), ], debug=True)
关键细节:
- 使用
google.auth.jwt.verify可以自动验证Token的签名、过期时间、受众等核心信息,无需手动处理复杂的加密逻辑。 - 可选的邮箱后缀检查可以进一步缩小访问范围,确保只有本项目内的服务账号能调用这个接口。
权限配置(无需额外操作)
因为Cloud Function和App Engine同属一个项目,Cloud Function的默认服务账号(PROJECT_ID@appspot.gserviceaccount.com)已经拥有生成ID Token的权限,不需要额外添加IAM角色。如果后续遇到权限问题,可以检查是否给该服务账号添加了Service Account Token Creator角色(同项目下默认已包含)。
内容的提问来源于stack exchange,提问作者Jack tileman
相关产品推荐
相关产品推荐

