如何限制获取Google Maps API密钥的后端接口访问权限?
我的Web应用采用React前端+Node.js(Express)后端架构,集成了react-google-maps地图组件,该组件依赖于在Google Cloud控制台创建的API密钥。我已开发后端接口用于获取所需的API密钥,当前该功能可正常工作:请求成功后密钥会传入APIProvider,地图也能正常显示,且密钥未直接暴露在前端代码中。
但通过开发者工具的Network面板,可查看到后端请求的接口地址https://examplesite/fetchApiKey,直接在浏览器中访问该URL就能以JSON格式获取到API密钥。请问如何限制该接口的访问权限?
我已在GCP的“APIs and Services > Credentials”中设置了应用限制,确保密钥仅能被我的前端网站使用,这在一定程度上可防止滥用,但我希望能完全隐藏密钥。
我猜测需要在Cloud Run Functions的权限设置中操作,但仅能修改特定Google账号的权限;尝试设置Cloud Run的“Ingress”和“Authentication”可限制访问,但不知如何授权我的网站调用该接口。
前端代码片段
export function SokArrangement() { const [apiKey, setApiKey] = useState<string | null>(null); fetch('https://examplesite/fetchApiKey') .then(res => res.json()) .then(data => { setApiKey(data.apiKey); }); ... //other code return( ... //other code <APIProvider apiKey={apiKey} onLoad={() => console.log('Maps API has loaded.')}> <div style={{ height:"100vh", width:"100%" }}> <Map defaultZoom={13} defaultCenter={ mapposition } mapId={"7ff7bc8394287bed"}> <ClusterMarkers addresses={addresses}/> //Generates various markers </Map> </div> </APIProvider> ) }
后端代码片段
import { onRequest } from "firebase-functions/v2/https"; import express from 'express'; import cors from 'cors'; const app = express(); app.use(cors({ origin: ['https://examplesite'] })); app.get('/apiKey', (req, res) => { res.json({ apiKey: 'aPiKeYsTuFf123456789' }); }); export const getApiKey = onRequest(app);
1. 加强请求校验,拦截非法访问
当前的CORS仅限制了请求来源,可以叠加多层校验,拦截直接通过地址栏发起的请求:
修改后端接口逻辑:
app.use(cors({ origin: ['https://examplesite'], credentials: true })); app.get('/apiKey', (req, res) => { // 校验Referer头,确保请求来自前端页面而非直接访问 const referer = req.get('Referer'); if (!referer || !referer.startsWith('https://examplesite/')) { return res.status(403).json({ error: 'Forbidden' }); } // 可选:添加自定义请求头校验,进一步过滤非法请求 const authHeader = req.get('X-App-Auth'); if (authHeader !== process.env.APP_AUTH_TOKEN) { return res.status(403).json({ error: 'Forbidden' }); } res.json({ apiKey: process.env.GOOGLE_MAPS_API_KEY }); });
前端请求时添加自定义头:
fetch('https://examplesite/fetchApiKey', { headers: { 'X-App-Auth': 'your-predefined-token' // 与后端环境变量值一致 } }) .then(res => res.json()) .then(data => setApiKey(data.apiKey));
2. 基于用户身份验证限制访问
如果应用有用户登录系统,可借助Firebase Auth验证请求身份,仅允许已登录的合法用户获取密钥:
前端携带ID Token请求
import { getAuth, getIdToken } from "firebase/auth"; // ... const auth = getAuth(); getIdToken(auth.currentUser) .then(idToken => { return fetch('https://examplesite/fetchApiKey', { headers: { 'Authorization': `Bearer ${idToken}` } }); }) .then(res => res.json()) .then(data => setApiKey(data.apiKey));
后端验证ID Token
import { getAuth } from "firebase-admin/auth"; import admin from "firebase-admin"; admin.initializeApp(); app.get('/apiKey', async (req, res) => { const idToken = req.headers.authorization?.split('Bearer ')[1]; if (!idToken) { return res.status(401).json({ error: 'Unauthorized' }); } try { await getAuth().verifyIdToken(idToken); // 验证通过,返回密钥 res.json({ apiKey: process.env.GOOGLE_MAPS_API_KEY }); } catch (error) { res.status(403).json({ error: 'Invalid token' }); } });
3. 后端代理地图请求,彻底隐藏密钥
完全避免前端接触密钥的最优方案是由后端代理所有地图相关请求:
- 前端不直接调用Google Maps API,而是将地图操作请求发送到你的后端接口
- 后端携带密钥调用Google Maps API,处理结果后返回给前端
- 这种方式需要重构部分地图逻辑,但能从根源上防止密钥泄露
4. 配置Cloud Run Functions访问控制
如果后端部署在Cloud Run(Firebase Functions托管于Cloud Run),可通过以下方式限制访问:
- 设置Ingress控制:将Ingress改为"Internal only"或"Allow internal traffic and Cloud Load Balancing",仅允许内部服务或负载均衡的请求访问
- 启用身份验证:开启"Require authentication",然后为前端服务(或负载均衡器)添加
Cloud Run Invoker角色权限- 进入Cloud Run控制台,找到目标函数服务
- 进入"Permissions"页面,添加对应主体(如项目服务账号、IAP用户组)并授予角色
内容的提问来源于stack exchange,提问作者Åsmund Vassbotn

