passport.js创建的session如何使用以实现登录鉴权与CRUD
Passport+Session 认证后续实现方案
你现有代码已经完成了session存储、passport序列化/反序列化、登录校验的核心逻辑,只需要补全以下环节就能实现登录后自由操作自有数据的效果。
1. 登录成功后服务端返回内容说明
你用的是Session-Cookie 认证模式,不需要像JWT方案一样手动返回token给前端存储:
- 你代码里调用
req.logIn(user, cb)成功后,express-session会自动生成session文档存入MongoDB的sessions集合,同时在响应头添加Set-Cookie字段,把session标识(默认名为connect.sid)写入浏览器Cookie - 接口响应只需要返回登录成功状态、当前用户的非敏感公开信息即可(比如用户ID、邮箱,绝对不能返回密码哈希),示例:
req.logIn(user, function(err){ if(err){ return res.status(400).json({errors: err}); } return res.status(200).json({ success: true, user: { id: user.id, email: user.email } }) })
你代码里注释提问的
req.logIn作用:这是Passport提供的登录态写入入口,调用后会触发你写的serializeUser逻辑,把用户ID存入当前session,是整个登录态生效的核心步骤。
2. 基于已存MongoDB Session的请求鉴权实现
你已经在入口文件注册了passport.initialize()和passport.session()两个中间件,这两个组件已经自动完成了session解析工作:
- 每次前端请求携带合法Cookie时,
express-session会从Cookie中提取session ID,去MongoDB的sessions集合匹配对应会话数据 passport.session()会从会话数据中取出之前存入的用户ID,自动调用你写的deserializeUser方法查询用户信息,把查到的当前登录用户对象挂载到req.user上
你只需要写一个通用登录校验中间件,挂到所有需要登录才能访问的路由上即可:
// 新建utils/auth.js存放鉴权中间件 const isAuthenticated = (req, res, next) => { // Passport自带判断方法,检测当前请求是否携带有效登录态 if (req.isAuthenticated()) { return next() } return res.status(401).json({ errors: "未登录,请先登录" }) } module.exports = isAuthenticated
中间件使用示例:
// 路由文件中引入 const isAuthenticated = require('../utils/auth') // 单个路由挂载 router.get('/profile', isAuthenticated, (req, res) => { // 这里直接取req.user就是当前登录用户信息,不需要重复查库 res.json({ user: req.user }) }) // 或者给整组路由统一挂载,组内所有接口都需要登录 router.use('/api/private', isAuthenticated, privateRoutes)
3. 自有数据CRUD的权限控制逻辑
核心规则:所有数据库操作强制绑定当前登录用户ID作为过滤条件,绝对不要信任前端传入的用户ID参数
假设你的业务数据模型(比如笔记、待办)都有owner字段关联创建者的用户ID,CRUD写法参考:
- 查询列表:只查归属当前用户的数据,不要查全表
// 错误写法:Todo.find({}) 会返回所有用户的数据 // 正确写法 const myTodos = await Todo.find({ owner: req.user._id }) - 单条查询/更新/删除:除了匹配数据ID,必须加owner校验,避免越权操作其他用户的数据
// 错误写法:Todo.findByIdAndUpdate(req.params.id, updateData) 只要知道数据ID就能改别人的内容 // 正确写法 const targetTodo = await Todo.findOneAndUpdate( { _id: req.params.id, owner: req.user._id }, updateData, { new: true } ) if (!targetTodo) return res.status(403).json({ errors: "无操作权限" }) - 新增数据:强制把数据归属人设为当前登录用户,不要使用前端传的用户标识
const newTodo = await Todo.create({ content: req.body.content, owner: req.user._id // 强制赋值,忽略前端传的owner字段 })
4. 必须补全的配置(否则Session不生效)
你现有代码缺几个关键配置,会导致前端请求无法携带Cookie、后端识别不到登录态:
- 修改CORS配置,允许跨域携带凭证
// 原来的app.use(cors())替换为 app.use(cors({ origin: "你的前端访问地址,比如http://localhost:3000", // 不能设为*,否则凭证配置不生效 credentials: true })) - 前端请求配置开启携带Cookie:如果用axios,全局配置
axios.defaults.withCredentials = true;如果用fetch,请求加credentials: 'include'选项 - 优化Session配置,减少无效存储、提升安全性
app.use(session({ secret: process.env.SESSION_SECRET, // 不要硬编码密钥,放到环境变量里 resave: false, saveUninitialized: false, // 改为false,未登录的请求不生成无效session存入MongoDB store: MongoStore.create({ mongoUrl: process.env.ATLAS_URI }), cookie: { maxAge: 1000 * 60 * 60 * 24, // 登录态有效期1天,可按需调整 httpOnly: true, // 禁止前端JS读取Cookie,防范XSS窃取登录态 secure: process.env.NODE_ENV === 'production' // 生产环境HTTPS下开启 } })) - 补充登出接口,Passport自带登出方法:
router.post("/logout", (req, res, next) => { req.logout(function(err) { if (err) return next(err) res.json({ success: "已退出登录" }) }) })
内容的提问来源于stack exchange,提问作者benwl
相关产品推荐
相关产品推荐

