我正在读一段代码,它有两个文件,如下所示:
使用currentuser
中间件的第一个文件:
const router = express.Router();
router.get("/api/users/currentuser", currentUser, (req, res) => {
res.send({ currentUser: req.currentUser || null });
});
export { router as currentUserRouter };
定义中间件的第二个文件:
interface UserPayload {
id: string;
email: string;
}
declare global {
namespace Express {
interface Request {
currentUser?: UserPayload;
}
}
}
export const currentUser = (
req: Request,
res: Response,
next: NextFunction
) => {
if (!req.session?.jwt) {
return next();
}
try {
const payload = jwt.verify(
req.session.jwt,
process.env.JWT_KEY!
) as UserPayload;
req.currentUser = payload;
} catch (err) {}
next();
};
我知道,如果有一个经过验证的jwt
令牌,中间件将从中取出有效负载,并将其添加到req
对象中。但是,如果它失败了,并且无法将有效负载/当前用户添加到req
中,该怎么办?下面的请求会发生什么,res
对象会是什么样子?
router.get("/api/users/currentuser", currentUser, (req, res) => {
res.send({ currentUser: req.currentUser || null });
});
你能编辑这个get
请求吗?以显示如果我不是中间件的编写者,我如何捕捉可能的错误?
如果您有一个catchall异常处理程序,而您的中间件抛出了一个异常,那么您将确定响应。
如果您的中间件抛出了一个异常,而您没有捕捉到它,那么系统可能会退出该进程。
如果您的中间件没有抛出异常,也没有调用next((,也没有响应,那么请求将挂起。
如果您的中间件返回了响应,并且没有调用next((,那么您的send函数将永远不会被调用。
最重要的是,您需要将响应转储到服务器上,并查看中间件是如何处理的。
在我的大多数身份验证中间件中,我选择不调用next((,并返回403错误。但是抛出一个异常,然后从catchall处理程序返回403,也有一些好处。
您需要用错误HTTP状态代码和正文中的错误消息进行响应。确切的状态和消息取决于异常的类型及其参数,因此您需要捕获并检查它
当前的express中间件不处理错误,只是不设置req.currentUser = payload;
,所以您不会了解用户。我认为这不是一个正确的身份验证错误解决方案。
在文档中,您可以看到如何处理错误:https://expressjs.com/en/guide/using-middleware.html
app.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).send('Something broke!')
})
所以我会重写代码,如果JWT验证失败,那么我会返回例如401未经授权的代码。https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401
我猜您正在使用JWT库:https://github.com/auth0/node-jsonwebtoken根据文档和代码,有3种类型的错误:TokenExpiredError、JsonWebTokenError、NotBeforeError用于验证。在这里,您可以检查它们何时被抛出:https://github.com/auth0/node-jsonwebtoken/blob/master/verify.js,以下是它们的定义:https://github.com/auth0/node-jsonwebtoken/tree/master/lib
因此,在catch块中,您只需使用instanceof
(例如if (err instanceof jwt.JsonWebTokenError) ...
(检查错误的类型,然后使用res.status(401)
相应地发送消息,并将next()
放在try块的末尾,因为只有在验证没有失败的情况下才应该调用它。