Express.js结合Firestore实现服务端用户登录状态判断及视图切换
问题核心原因
TypeError: admin.auth(...).onAuthStateChanged is not a function
该报错是因为onAuthStateChanged是客户端Firebase Auth SDK专属的状态监听方法,Firebase Admin服务端SDK没有提供这个API——服务端本身不会持久化存储单个客户端用户的登录状态,所有登录态校验都依赖客户端请求携带的身份凭证完成。
服务端实现登录态判断的正确方案
服务端做登录态校验完全符合SSR(服务端渲染)场景的需求,不会出现客户端判断登录态导致的页面闪屏问题,是合理的技术选择,实现逻辑如下:
步骤1:客户端登录后传递身份凭证
客户端调用Firebase Auth完成登录/注册后,会拿到当前用户的ID Token,你需要将该Token存储到客户端的HttpOnly类型Cookie中(推荐命名为__session,适配绝大多数云服务的Cookie转发规则),或者在每次请求时放到Authorization请求头中,以Bearer <Token>格式携带。
步骤2:服务端校验Token并返回对应视图
服务端收到根路径请求后,先提取请求携带的ID Token,调用Admin SDK的verifyIdToken方法校验Token合法性,校验通过则说明用户处于登录状态,否则返回登录页。
修正后的代码示例
const admin = require('firebase-admin') const cookieParser = require('cookie-parser') // 记得注册cookie解析中间件 app.use(cookieParser()) // 从请求中提取ID Token的工具方法 const extractIdToken = (req) => { // 优先读取Cookie中的Token if (req.cookies?.__session) return req.cookies.__session // 其次读取Authorization头中的Token const authHeader = req.headers.authorization if (authHeader?.startsWith('Bearer ')) return authHeader.split(' ')[1] return null } app.get('/', async (req, res) => { const idToken = extractIdToken(req) // 无Token直接返回登录页 if (!idToken) return res.render('auth') try { // 校验Token合法性,拿到用户uid const decodedToken = await admin.auth().verifyIdToken(idToken) const uid = decodedToken.uid // 替换你之前写死的固定ID,用当前登录用户的uid查询数据 const restaurantData = await getRestaurant(uid) const [ambassadorList, activityList] = await Promise.all([ getAmbassadorInfo(uid), getActivityFeed(uid) ]) res.render('dashboard', { restaurantName: restaurantData.name, totalScans: restaurantData.total_scans, ambassadorList, activityList }) } catch (error) { // Token过期、伪造等校验失败场景,返回登录页 console.error('身份校验失败:', error) res.render('auth') } })
可选的更优方案(依技术架构而定)
- 如果你用的是SSR架构,上述服务端校验的方案就是最优选择,安全性和用户体验都更好。
- 如果你用的是前后端分离的SPA(单页应用)架构,可以把登录态判断逻辑放到客户端实现:直接调用客户端Firebase Auth的
onAuthStateChanged方法监听状态,未登录直接跳转登录页,服务端只负责接口的鉴权校验即可,能降低服务端的渲染压力。
内容的提问来源于stack exchange,提问作者Shaheryar Ajmal
相关产品推荐
相关产品推荐

