如何在Express+Passport.js的控制器中全局使用currentUser变量?
在所有Express控制器中便捷访问Passport.js的currentUser
嘿,这个需求挺常见的,其实借助Express的中间件特性,就能轻松实现让所有控制器便捷拿到当前用户信息,给你分享几个实用的方案:
方案一:利用已有的全局中间件直接访问res.locals.currentUser
你已经写了把currentUser传到视图的全局中间件,其实控制器里也能直接访问res.locals.currentUser!这是最省事的方法,不用额外加新代码:
// 你已经配置好的全局中间件 app.use(function(req, res, next){ res.locals.currentUser = req.user; next(); }); // 在任意控制器里直接使用 app.get('/posts', async (req, res, next) => { const currentUser = res.locals.currentUser; // 先处理用户未登录的情况 if (!currentUser) { return res.redirect('/login'); } // 用currentUser做数据库查询,比如检查用户是否点赞过帖子 const posts = await Post.find({}); const postsWithLikeStatus = posts.map(post => ({ ...post.toObject(), hasLiked: post.likes.includes(currentUser._id) })); res.render('posts', { posts: postsWithLikeStatus }); });
方案二:自定义控制器包装函数,自动传入currentUser
如果觉得每次写res.locals.currentUser还是有点繁琐,可以写一个简单的包装函数,把currentUser直接作为参数传给控制器,让代码更简洁:
// 定义一个包装函数,自动注入currentUser const withCurrentUser = (controller) => { return (req, res, next) => { // 把Passport提供的req.user作为参数传给目标控制器 controller(req, res, next, req.user); }; }; // 使用包装后的控制器 app.get('/posts', withCurrentUser(async (req, res, next, currentUser) => { if (!currentUser) { return res.redirect('/login'); } // 直接用currentUser操作数据库 const userLikedPosts = await Post.find({ likes: currentUser._id }); // ...其他业务逻辑 res.render('posts', { likedPosts: userLikedPosts }); }));
关键注意事项
- 确保你的路由已经通过Passport的认证中间件保护(比如
passport.authenticate('local', { session: true })),否则req.user会是undefined,记得在控制器里先判断用户是否登录。 - 如果是API接口(返回JSON而非渲染视图),两种方案同样适用,只需要把
res.render换成res.json即可。
内容的提问来源于stack exchange,提问作者Travis Kapper
相关产品推荐
相关产品推荐

