Node.js JWT认证中间件疑问:仅验签还是需查库?错误处理问题
关于JWT认证中间件的两个疑问解答
疑问1:验证JWT时查询数据库是否违背设计初衷?
- JWT的「无状态」设计初衷是不需要在服务端存储会话数据,避免依赖会话存储(比如Redis),但这不代表完全不能查询数据库。
- 你现在查询数据库的场景是获取用户完整信息或验证用户是否仍有效(比如是否被封禁),这是实际开发中很常见的需求,完全合理:
- 如果业务只需要
userId,可以直接从JWT payload中取出使用,不用查库; - 如果需要用户的最新状态、权限等信息,必须查库确保数据是最新的,这时候查询数据库反而能弥补JWT payload无法实时更新的缺点。
- 如果业务只需要
- 所以这种做法并没有违背JWT的设计初衷,是业务需求下的合理选择。
疑问2:数据库连接失败的错误无法被捕获?
- 问题出在异步代码的错误捕获范围:外层的
try/catch只能捕获同步代码的错误,而jwt.verify的回调是异步函数,里面的await User.findById抛出的错误不在外层try的捕获范围内。 - 解决方法有两种:
- 改用
jwt.verify的同步版本(不带回调),把整个逻辑放在async函数里:module.exports = async (req, res, next) => { const { authorization } = req.headers; try { if (!authorization) return res.status(401).send({error: 'you must be logged in'}); const token = authorization.replace('Bearer ', ""); // 同步版本的verify,直接返回payload const payload = jwt.verify(token, 'MY_SECRET_KEY'); const {userId} = payload; const user = await User.findById(userId); if (!user) return res.status(401).send({error: 'you must be logged in'}); req.user = user; next(); } catch (err) { // 这里可以捕获同步verify的错误,以及await的异步错误 res.status(400).send("too bad its an err"); } }; - 在异步回调内部添加
try/catch:module.exports = (req, res, next) => { const { authorization } = req.headers; try { if (!authorization) return res.status(401).send({error: 'you must be logged in'}); const token = authorization.replace('Bearer ', ""); jwt.verify(token, 'MY_SECRET_KEY', async (err, payload) => { if (err) return res.status(401).send({error: 'you must be logged in'}); try { const {userId} = payload; const user = await User.findById(userId); if (!user) return res.status(401).send({error: 'you must be logged in'}); req.user = user; next(); } catch (dbErr) { res.status(400).send("too bad its an err"); } }) } catch (err) { res.status(400).send("too bad its an err"); } };
- 改用
- 推荐第一种方案,代码更简洁,错误捕获逻辑更统一。
内容的提问来源于stack exchange,提问作者learncode
相关产品推荐
相关产品推荐

