Fastify自定义ACL中间件开发两类技术问题咨询
Fastify自定义ACL中间件优化方案
问题1:异步preHandler优化,避免多次返回401
Fastify的异步preHandler中间件不需要手动调用next()或done()——只要你的异步函数正常执行完毕(没有抛出错误或发送响应),Fastify会自动进入下一个中间件/路由处理函数。
你当前的问题大概率是每个中间件都独立判断并返回401,导致重复触发响应。优化思路如下:
- 每个中间件只负责自身验证逻辑:验证通过就直接结束函数(不做响应操作),让流程自然流转到下一个环节;
- 仅在验证不通过时,调用
reply.code(401).send({ message: 'Unauthorized' }),此时Fastify会终止后续中间件执行,不会出现多次返回401的情况。
示例代码参考:
// authMiddleware.mjs export default async function authMiddleware(request, reply) { const token = request.headers.authorization?.split(' ')[1]; if (!token) { return reply.code(401).send({ message: 'Missing auth token' }); } // 验证token并获取用户信息 const user = await verifyToken(token); if (!user) { return reply.code(401).send({ message: 'Invalid token' }); } // 将用户信息挂载到request,供后续中间件使用 request.user = user; }
如果想统一处理所有401场景,可以注册Fastify全局错误处理器:
fastify.setErrorHandler((error, request, reply) => { if (error.statusCode === 401) { reply.code(401).send({ message: 'Unauthorized access' }); } else { reply.code(error.statusCode || 500).send({ message: error.message }); } });
之后中间件验证不通过时,只需抛出带状态码的错误即可:
throw Object.assign(new Error('Invalid token'), { statusCode: 401 });
问题2:让ACL中间件支持动态传入角色数组
把aclMiddleware改成高阶函数,让它接收角色数组参数后,返回符合FastifypreHandler规范的函数,就能实现动态传参。
实现代码:
// aclMiddleware.mjs export default function aclMiddleware(allowedRoles) { // 返回实际的preHandler处理函数 return async function (request, reply) { const userRole = request.user?.role; if (!userRole || !allowedRoles.includes(userRole)) { return reply.code(401).send({ message: 'Insufficient permissions' }); } }; }
路由中使用方式如下:
// brandRoute.mjs import authMiddleware from './authMiddleware.mjs'; import aclMiddleware from './aclMiddleware.mjs'; export default async function brandRoutes(fastify) { fastify.get('/brands', { preHandler: [authMiddleware, aclMiddleware(['Administrator', 'Editor'])], }, async (request, reply) => { return { data: [] }; }); fastify.post('/brands', { preHandler: [authMiddleware, aclMiddleware(['Administrator'])], }, async (request, reply) => { return { message: 'Brand created' }; }); }
这种写法既保留了中间件的复用性,又能根据不同路由的权限需求动态配置允许的角色。
内容的提问来源于stack exchange,提问作者Jeet Chowdhury
相关产品推荐
相关产品推荐

