如何安全保护Cloud Run API?仅允许Firebase React前端调用
解决方案:安全保护Cloud Run API,仅限你的React前端调用
一、核心原则:绝对禁止客户端持有服务账号密钥
服务账号密钥属于敏感凭据,一旦暴露在前端代码中,任何人都能冒充你的服务账号操作云资源,这是必须严格遵守的安全规则。下面的方案完全不需要客户端存储任何密钥。
二、配置Cloud Run的IAM权限,限制访问范围
- 进入Cloud Run控制台,找到你的后端服务,打开「权限」标签页
- 移除
allUsers权限(如果还存在),确保服务不再公开可访问 - 添加以下成员之一,授予**「Cloud Run 调用者」(roles/run.invoker)**权限:
- 若仅允许经过Firebase Auth登录的用户访问:添加成员
allAuthenticatedUsers - 若要更严格地限制为你自己Firebase项目下的用户:添加成员
principal://iam.googleapis.com/projects/<你的GCP项目ID>/locations/global/workloadIdentityPools/firebase/providers/firebase/google.subject,并设置条件为request.auth.claims.firebase.project_id == "<你的Firebase项目ID>"
- 若仅允许经过Firebase Auth登录的用户访问:添加成员
三、前端通过Firebase Auth获取合法凭证调用API
利用Firebase Auth生成身份令牌,无需密钥即可完成安全认证:
- 确保React项目已集成Firebase Auth(若未集成,先完成初始化配置)
- 获取当前登录用户的ID Token:
async function getIdToken() { const user = firebase.auth().currentUser; if (!user) { throw new Error("用户未登录,请先完成认证"); } return await user.getIdToken(); } - 调用Cloud Run API时,将Token放入请求头:
async function callCloudRunApi() { const idToken = await getIdToken(); const response = await fetch("<你的Cloud Run服务URL>", { method: "GET", // 匹配你的API请求方法(POST/PUT等) headers: { "Authorization": `Bearer ${idToken}`, "Content-Type": "application/json" } // 按需添加请求体或参数 }); return await response.json(); }
四、(可选)后端添加Token校验,强化安全
虽然Cloud Run的IAM会自动验证Token,但你可以在FastAPI后端额外校验Token来源,确保请求来自你的Firebase项目:
- 安装依赖库:
pip install pyjwt cryptography - 编写Token验证依赖:
import jwt from fastapi import Depends, HTTPException, Request from jwt.exceptions import InvalidTokenError from jwt import PyJWKClient FIREBASE_PROJECT_ID = "<你的Firebase项目ID>" async def verify_firebase_token(request: Request): auth_header = request.headers.get("Authorization") if not auth_header or not auth_header.startswith("Bearer "): raise HTTPException(status_code=401, detail="缺少有效身份凭证") token = auth_header.split(" ")[1] try: jwks_client = PyJWKClient("https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com") signing_key = jwks_client.get_signing_key_from_jwt(token) payload = jwt.decode( token, signing_key.key, algorithms=["RS256"], audience=FIREBASE_PROJECT_ID, issuer=f"https://securetoken.google.com/{FIREBASE_PROJECT_ID}" ) return payload except InvalidTokenError: raise HTTPException(status_code=401, detail="无效的身份凭证") # 在路由中使用该依赖 @app.get("/your-api-endpoint") async def protected_endpoint(payload: dict = Depends(verify_firebase_token)): return {"message": "请求合法", "user_id": payload["user_id"]}
五、(可选)用Firebase Hosting重写规则隐藏Cloud Run URL
在firebase.json中配置重写,让前端调用Firebase Hosting路径即可转发到Cloud Run,进一步隐藏后端地址:
{ "hosting": { "public": "build", "rewrites": [ { "source": "/api/**", "run": { "serviceId": "<你的Cloud Run服务ID>", "region": "<你的Cloud Run部署区域>" } } ] } }
配置完成后,前端只需调用/api/xxx路径,Firebase Hosting会自动完成请求转发并保留权限验证逻辑。
内容的提问来源于stack exchange,提问作者DownForProxy
相关产品推荐
相关产品推荐

