如何让所有Express路由自动使用验证逻辑无需重复编写代码?
如何在Express中复用带Firebase认证的路由配置?
我完全懂你不想重复复制粘贴代码的心情——重复代码不仅维护麻烦,还容易引入不一致的问题。你之前共享路由实例出问题,大概率是因为多个模块复用了同一个express.Router()实例,导致路由冲突或者中间件重复挂载。这里给你两种简洁的解决方案,让所有路由都能复用这套配置:
方案1:用路由工厂函数生成预配置的Router
这种方式最灵活,每个业务路由都会得到一个独立的、已配置好中间件的Router实例,完全避免实例共享的问题。
步骤1:抽离通用中间件和认证逻辑
先创建一个auth-middleware.js文件,把通用的中间件和Firebase认证逻辑单独抽出来:
const express = require("express"); const cookieParser = require('cookie-parser')(); const cors = require('cors')({origin: true}); const firebase = require("./firebase.js"); // 导出Firebase认证中间件 exports.validateFirebaseIdToken = (req, res, next) => { if ((!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) && !req.cookies.__session) { res.status(403).send({"error": 'Unauthorized'}); return; } let idToken; if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) { idToken = req.headers.authorization.split('Bearer ')[1]; } else { idToken = req.cookies.__session; } firebase.admin.auth().verifyIdToken(idToken) .then((decodedIdToken) => { req.user = decodedIdToken; return next(); }) .catch(error => { res.status(403).send({"error": 'Unauthorized'}); }); }; // 导出通用中间件集合 exports.commonMiddlewares = [cors, cookieParser, exports.validateFirebaseIdToken];
步骤2:创建路由工厂函数
再写一个create-router.js,作为生成预配置Router的工厂:
const express = require("express"); const { commonMiddlewares } = require('./auth-middleware'); // 工厂函数:每次调用返回一个全新的、已配置好中间件的Router function createRouter(requiresAuth = true) { const router = express.Router(); // 挂载通用中间件 router.use(...commonMiddlewares); // 可选:根据参数决定是否启用认证(默认启用) if (!requiresAuth) { // 如果不需要认证,移除认证中间件(或者直接调整中间件集合) router.stack = router.stack.filter(mw => mw.handle.name !== 'validateFirebaseIdToken'); } return router; } module.exports = createRouter;
步骤3:在业务路由中使用工厂函数
比如你的user-router.js可以这样写,完全不用重复配置:
const createRouter = require('./create-router'); // 创建一个带认证的Router实例 const router = createRouter(); // 在这里添加你的业务路由逻辑 router.get('/profile', (req, res) => { res.send({ message: '用户信息', user: req.user }); }); module.exports = router;
如果有公开路由不需要认证,只需要调用createRouter(false)即可:
const router = createRouter(false); router.get('/public', (req, res) => { res.send({ message: '公开内容' }); });
方案2:创建基础Router让业务路由继承
如果你喜欢更简洁的方式,可以创建一个基础Router,让所有业务路由通过router.use()来继承它的中间件配置:
步骤1:创建基础配置的Router
在base-router.js中:
const express = require("express"); const cookieParser = require('cookie-parser')(); const cors = require('cors')({origin: true}); const firebase = require("./firebase.js"); const baseRouter = express.Router(); // 挂载通用中间件 baseRouter.use(cors); baseRouter.use(cookieParser); // 添加认证中间件 baseRouter.use((req, res, next) => { if ((!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) && !req.cookies.__session) { res.status(403).send({"error": 'Unauthorized'}); return; } let idToken; if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) { idToken = req.headers.authorization.split('Bearer ')[1]; } else { idToken = req.cookies.__session; } firebase.admin.auth().verifyIdToken(idToken) .then((decodedIdToken) => { req.user = decodedIdToken; return next(); }) .catch(error => { res.status(403).send({"error": 'Unauthorized'}); }); }); module.exports = baseRouter;
步骤2:业务路由继承基础Router
在业务路由文件中,创建自己的Router并use基础Router:
const express = require("express"); const baseRouter = require('./base-router'); const router = express.Router(); // 继承基础路由的所有中间件配置 router.use(baseRouter); // 添加业务路由 router.post('/update', (req, res) => { res.send({ message: '更新成功', userId: req.user.uid }); }); module.exports = router;
为什么之前共享路由实例会出问题?
当你在多个模块中导入同一个express.Router()实例时,所有模块的路由都会被添加到这个实例上,最终导致路由路径冲突、中间件重复执行的问题。而上面两种方案,要么给每个业务路由生成独立的Router实例,要么让业务路由继承基础配置但保持自身实例独立,完美解决了这个问题。
内容的提问来源于stack exchange,提问作者Tometoyou
相关产品推荐
相关产品推荐

