Express项目鉴权最终中间件实践合理性及CRUD方法适配咨询
问题1:当前实现是否属于不良实践
你的实现思路有可借鉴的优势:将鉴权、持久化、响应逻辑统一收口,能避免在多个控制器中重复编写同类代码,且提前把修改存在内存、鉴权通过后再持久化的设计,确实能避免未授权操作写入数据库。但该实现仍存在几处明显的不合理问题,属于有缺陷的实践:
- 鉴权分支逻辑不完整:当前代码中鉴权失败仅打印日志,没有中断后续的save和返回逻辑,未授权用户仍然会触发数据持久化,属于严重的逻辑漏洞
- 容错性极低:强依赖上游控制器为
req挂载document和validateFields两个属性,只要任意控制器漏写其中一个,就会直接抛出异常导致服务报错 - 职责过载:单个中间件同时承担鉴权、持久化、响应三个完全独立的职责,不符合单一职责原则,后续调整某一个逻辑的成本会很高
- 适配场景有限:仅支持修改后调用
save的场景,无法适配你提到的原子更新、删除等操作,扩展性差
问题2:处理立即持久化的数据库操作
核心思路是不要在控制器中直接执行findByIdAndUpdate/findByIdAndDelete这类会立即写入数据库的方法,改为将操作类型、参数挂载到req上,统一放在鉴权通过后执行,适配你现有架构的改造方案如下:
- 控制器侧仅声明操作信息,不执行实际数据库写入
// 删除操作示例 req.operation = { type: 'delete', model: Order, // 对应的Mongoose模型 query: { _id: orderId } // 操作的查询条件 } req.validateFields = [ order.senderId._id.toString(), order.recieverId._id.toString(), order.driverId._id.toString(), ] next() // 原子更新操作示例 req.operation = { type: 'update', model: Order, query: { _id: orderId }, updateData: { status: 'completed' }, options: { new: true } // 返回更新后的数据 } req.validateFields = [/* 权限校验字段 */] next()
- 统一中间件先鉴权,再根据操作类型执行对应数据库操作
app.use(async (req, res, next) => { // 先做参数合法性校验 if (!req.validateFields || !req.user?._id) { return res.status(400).json({ msg: '请求参数异常' }) } // 鉴权逻辑 if (!req.validateFields.includes(req.user._id.toString())) { return res.status(403).json({ msg: '无操作权限' }) } // 鉴权通过后执行对应操作 let result try { if (req.document) { // 原有save场景 result = await req.document.save() } else if (req.operation) { const { type, model, query, updateData, options } = req.operation switch(type) { case 'delete': result = await model.findOneAndDelete(query) break case 'update': result = await model.findOneAndUpdate(query, updateData, options) break // 可扩展其他操作类型 } } res.status(200).json({ document: result }) } catch (err) { res.status(500).json({ msg: '操作失败', error: err.message }) } })
内容的提问来源于stack exchange,提问作者Lhon Rafaat Mohammed
相关产品推荐
相关产品推荐

