服务端集成Firebase Authentication实现路由鉴权的方法咨询
问题说明
你当前用的纯前端sessionStorage鉴权方案完全没有安全性:用户可以直接通过浏览器开发者工具篡改sessionStorage里的用户字段,也可以直接禁用页面JavaScript绕过校验,直接获取seller.html的全部内容,不存在任何防护能力。
你已经在项目里引入了firebase-admin服务端SDK,完全可以直接在服务端完成鉴权逻辑,不需要依赖客户端SDK实现路由保护。
具体实现方案
前置依赖安装
先安装cookie解析依赖,用来读取请求携带的cookie:
npm i cookie-parser
第一步:修改服务端基础配置
在server.js中引入cookie-parser并注册中间件:
const cookieParser = require('cookie-parser'); // 放在express.json()后面即可 app.use(cookieParser());
第二步:编写通用鉴权中间件
这个中间件会在所有受保护路由加载前执行,校验用户登录状态和权限:
async function requireAuth(req, res, next) { // 从cookie里取Firebase的身份凭证 const idToken = req.cookies.firebaseToken; if (!idToken) return res.redirect('/login'); try { // 用admin SDK验证token合法性,伪造、过期的token会直接抛出异常 const decodedToken = await admin.auth().verifyIdToken(idToken); // 校验用户是否具备seller权限,这里的自定义claims由服务端控制,用户无法篡改 if (decodedToken.seller !== true) return res.status(403).send('您没有访问该页面的权限'); // 将解析后的用户信息挂载到req对象上,后续路由可直接使用 req.user = decodedToken; next(); } catch (error) { // token无效时清除残留cookie,跳转登录页 res.clearCookie('firebaseToken'); return res.redirect('/login'); } }
第三步:添加登录/登出接口
客户端登录成功拿到Firebase ID Token后,调用该接口把凭证存到安全Cookie中:
// 登录接口,接收客户端传来的ID Token app.post('/api/auth/login', async (req, res) => { const { idToken } = req.body; try { // 先校验token合法性 await admin.auth().verifyIdToken(idToken); // 设置HttpOnly Cookie,前端JavaScript无法读取,避免XSS攻击窃取凭证 res.cookie('firebaseToken', idToken, { httpOnly: true, secure: process.env.NODE_ENV === 'production', // 生产环境部署在HTTPS上时开启 maxAge: 3600 * 1000, // 有效期和Firebase ID Token默认时长一致,为1小时 sameSite: 'strict' }); res.json({ code: 0, msg: '登录成功' }); } catch (error) { res.status(401).json({ code: -1, msg: '登录凭证无效' }); } }); // 登出接口 app.post('/api/auth/logout', (req, res) => { res.clearCookie('firebaseToken'); res.redirect('/login'); });
第四步:改造客户端登录逻辑
客户端用Firebase Auth完成邮箱密码登录后,不要只把用户信息存在sessionStorage,要拿到ID Token发给刚才写的登录接口:
// 客户端登录成功回调逻辑示例 const userCredential = await signInWithEmailAndPassword(auth, email, password); const idToken = await userCredential.user.getIdToken(); // 把token发给服务端设置安全Cookie await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ idToken }) }); // 登录完成后跳转到卖家后台 window.location.href = '/seller';
第五步:给受保护路由挂载鉴权中间件
修改原来的/seller路由,加入requireAuth中间件:
app.get('/seller', requireAuth, (req, res) => { res.sendFile(path.join(staticPath, "seller.html")); })
关键注意事项
- 所有前端层面的权限校验都只能做体验优化,真正的权限判定必须在服务端完成。只要服务端没做校验,静态文件就可以被任意用户直接访问。
- 用户的seller权限不要在前端设置,要通过
firebase-admin在服务端调用admin.auth().setCustomUserClaims(uid, { seller: true })给对应用户添加自定义声明,这个声明会被包含在ID Token中,由Firebase服务端签名,用户无法篡改。 - 你项目根目录下的
1234.json是Firebase服务端凭证,拥有项目的最高操作权限,绝对不能泄露,不要传到公开代码仓库,也不要打包到前端静态资源里。 - Firebase ID Token默认有效期1小时,可以在客户端加定时刷新逻辑,提前获取新的ID Token更新服务端Cookie,避免用户使用过程中因token过期被强制踢下线。
内容的提问来源于stack exchange,提问作者Mergo22
相关产品推荐
相关产品推荐

