You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

个人网站用户数据获取疑问:从DB查询还是req.user读取?

问题

我正在做一个提升编程能力的网站,开发用户profile页面时对用户数据获取方式存疑。

我觉得当前的userDetails控制器代码不够安全,因为同时在中间件中通过session的req.user获取用户信息。担心通过数据库查询获取数据时,任何人都能访问,存在安全隐患。

userDetails控制器代码:

module.exports.userDetails = async (req,res,next) => {

const {username} = req.params;
const user = await User.findOne({username}).populate({path: 'campgrounds'})
console.log(user)
if(!user){
    req.flash('error', 'Cannot access that username.')
    return res.redirect('/campgrounds')
}
res.render('users/details.ejs', {user})
}

中间件代码:

app.use((req,res,next) => {

res.locals.currentUser = req.user;
res.locals.currentUserDetails = req.user._doc;


  res.locals.success = req.flash('success');
   res.locals.error = req.flash('error');
   next();
})

解决方案建议
  • 拆分公开/私有数据:先明确profile页面哪些数据是所有人可看的(比如用户名、公开的campgrounds),哪些是仅限用户本人查看的(比如邮箱、隐私设置)。查询数据库时用select方法限制返回字段,避免敏感数据泄露,示例:

    const user = await User.findOne({username})
      .select('username campgrounds avatar') // 只取公开字段
      .populate({path: 'campgrounds'});
    
  • 加权限校验逻辑:在控制器里判断访问者身份,按需返回数据:

    module.exports.userDetails = async (req,res,next) => {
      const {username} = req.params;
      const user = await User.findOne({username}).populate({path: 'campgrounds'});
      if(!user){
          req.flash('error', 'Cannot access that username.')
          return res.redirect('/campgrounds')
      }
      // 判断是否是用户本人访问
      const isOwnProfile = req.user && req.user._id.toString() === user._id.toString();
      // 非本人访问时过滤敏感字段
      const displayUser = isOwnProfile ? user : {
          username: user.username,
          campgrounds: user.campgrounds,
          // 只保留允许公开的字段
      };
      res.render('users/details.ejs', {user: displayUser})
    }
    
  • 不要直接暴露req.user._doc:中间件里res.locals.currentUserDetails = req.user._doc风险很高,_doc包含Mongoose文档的原始数据,可能有密码哈希、邮箱等敏感内容。建议只提取需要的字段赋值:

    res.locals.currentUserDetails = {
      id: req.user._id,
      username: req.user.username,
      avatar: req.user.avatar
    };
    
  • 可选:强制登录访问:如果所有profile页面都需要登录才能查看,加一个登录验证中间件:

    const isLoggedIn = (req, res, next) => {
      if(!req.isAuthenticated()){
          req.flash('error', '请先登录!');
          return res.redirect('/login');
      }
      next();
    }
    // 给profile路由挂载该中间件
    app.get('/users/:username', isLoggedIn, userDetails);
    

内容的提问来源于stack exchange,提问作者Kelise

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 19:01:20