You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让所有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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:06:37