如何通过Firebase Admin SDK实现公、私有API端点共存?
我来帮你梳理下怎么把Express应用部署到Firebase Hosting+Cloud Functions,同时区分公网和需要身份验证的私有API端点,用Firebase Admin SDK搞定令牌验证的完整流程~
整体架构说明
简单说就是:前端静态资源托管在Firebase Hosting,后端Express服务跑在Cloud Functions上;前端请求后端时,私有接口需要携带Firebase ID令牌,通过我们写的中间件验证身份后才能访问,公网接口则直接开放。
步骤1:初始化项目与安装依赖
- 先确保本地装了
firebase-tools,没装的话跑npm install -g firebase-tools,然后登录Firebase账号:firebase login - 初始化项目:在项目根目录执行
firebase init,按提示勾选Functions和Hosting - 进入
functions目录,安装必需依赖:npm install express firebase-admin cors - 注意:Firebase Functions环境会自动给Admin SDK注入权限,不用手动下载服务账号密钥,直接初始化就行
步骤2:编写身份验证中间件
把验证ID令牌的逻辑抽成可复用的中间件,这样所有私有接口都能直接用:
const admin = require('firebase-admin'); admin.initializeApp(); // 验证Firebase ID令牌的中间件 const authenticate = async (req, res, next) => { const authHeader = req.headers.authorization; // 检查请求头是否带了Bearer令牌 if (!authHeader || !authHeader.startsWith('Bearer ')) { return res.status(401).json({ error: '请提供有效的身份令牌' }); } const idToken = authHeader.split(' ')[1]; try { // 验证并解码令牌 const decodedToken = await admin.auth().verifyIdToken(idToken); // 把解码后的用户信息挂载到req对象上,后续路由可以直接用 req.user = decodedToken; next(); // 验证通过,继续执行后续路由逻辑 } catch (error) { return res.status(403).json({ error: '身份令牌无效或已过期' }); } };
步骤3:配置Express路由(区分公网/私有)
创建Express实例,分别定义无需验证的公网接口和需要验证的私有接口:
const express = require('express'); const cors = require('cors'); const functions = require('firebase-functions'); const app = express(); // 全局中间件:处理跨域和JSON请求解析 app.use(cors({ origin: true })); app.use(express.json()); // 👉 公网API端点:所有人可直接访问 app.get('/api/public', (req, res) => { res.json({ message: '这是一个公网端点,无需登录就能访问~' }); }); // 👉 私有API端点:必须通过authenticate中间件验证身份 app.get('/api/private', authenticate, (req, res) => { res.json({ message: `欢迎访问私有端点,${req.user.email}!`, userInfo: { uid: req.user.uid, email: req.user.email, emailVerified: req.user.email_verified } }); }); // 把Express应用导出为Cloud Function exports.api = functions.https.onRequest(app);
步骤4:配置Hosting重写规则
让前端的API请求自动转发到Cloud Functions,修改项目根目录的firebase.json:
{ "hosting": { "public": "public", // 前端静态资源目录 "rewrites": [ { "source": "/api/**", // 所有/api开头的请求 "function": "api" // 转发到名为api的Cloud Function } ] } }
步骤5:前端请求示例
前端调用私有接口时,需要先从Firebase Auth获取当前用户的ID令牌,再放到请求头里:
import { getAuth, getIdToken } from "firebase/auth"; const auth = getAuth(); const currentUser = auth.currentUser; if (currentUser) { getIdToken(currentUser) .then(idToken => { // 调用私有API fetch('/api/private', { headers: { 'Authorization': `Bearer ${idToken}` } }) .then(res => res.json()) .then(data => console.log('私有接口返回:', data)) .catch(err => console.error('请求失败:', err)); }) .catch(err => console.error('获取令牌失败:', err)); } else { console.log('用户未登录,无法访问私有接口'); }
部署与测试
- 部署Cloud Functions:
firebase deploy --only functions - 部署Hosting:
firebase deploy --only hosting - 测试公网接口:直接访问
https://你的项目ID.web.app/api/public,应该返回正常响应 - 测试私有接口:未带令牌会返回401,带有效令牌返回用户信息,无效/过期令牌返回403
内容的提问来源于stack exchange,提问作者anonymous
相关产品推荐
相关产品推荐

