Node系列 · Express:登录与认证

发布时间:2026/10/23 3:47:59

Node系列 · Express:登录与认证 Node系列 · Express登录与认证登录与认证是后端最常见的需求。本章从登录接口设计到鉴权中间件把完整流程串起来——session 与 JWT 两种方案都会讲后续章节单独展开。一、登录与认证的核心流程数据库服务器客户端数据库服务器客户端alt[密码正确][密码错误]POST /api/auth/login{ email, password }SELECT user WHERE email?user (含 password hash)bcrypt.compare(password, hash)生成 sessionId / JWT200 OKSet-Cookie 或 { token }401 UnauthorizedGET /api/profileCookie: sessionIdxxx鉴权中间件验证200 OK 用户信息二、登录接口设计2.1 接口签名POST /api/auth/login Content-Type: application/json { email: aliceexample.com, password: plain-password }成功响应HTTP/1.1 200 OK Set-Cookie: sessionIdxxx; HttpOnly; Secure; SameSiteLax { user: { id: 1, name: Alice, email: aliceexample.com } }失败响应HTTP/1.1 401 Unauthorized { error: 邮箱或密码错误 }::: tip错误信息要模糊——“邮箱或密码错误而不是邮箱不存在或密码错误”。后者会泄露账号是否存在。:::2.2 Express 实现const express require(express); const bcrypt require(bcrypt); const router express.Router(); router.post(/login, async (req, res, next) { try { const { email, password } req.body; // 1. 验证请求体 if (!email || !password) { return res.status(400).json({ error: 邮箱和密码必填 }); } // 2. 查用户 const user await User.findOne({ where: { email } }); if (!user) { // 用同一条错误信息避免泄露账号是否存在 return res.status(401).json({ error: 邮箱或密码错误 }); } // 3. 验证密码 const isMatch await bcrypt.compare(password, user.passwordHash); if (!isMatch) { return res.status(401).json({ error: 邮箱或密码错误 }); } // 4. 设置会话这里用 sessionId详细见 session 章节 req.session.userId user.id; // 5. 返回用户信息不含密码 res.json({ user: { id: user.id, name: user.name, email: user.email, }, }); } catch (err) { next(err); } }); module.exports router;三、注册接口配套router.post(/register, async (req, res, next) { try { const { email, password, name } req.body; // 1. 验证 if (!email || !password) { return res.status(400).json({ error: 邮箱和密码必填 }); } if (password.length 8) { return res.status(400).json({ error: 密码至少 8 位 }); } // 2. 查重 const exists await User.findOne({ where: { email } }); if (exists) { return res.status(409).json({ error: 邮箱已被注册 }); } // 3. 密码哈希bcrypt 自动加盐 const passwordHash await bcrypt.hash(password, 10); // 4. 创建用户 const user await User.create({ email, name, passwordHash }); // 5. 自动登录 req.session.userId user.id; res.status(201).json({ user: { id: user.id, name: user.name, email: user.email }, }); } catch (err) { next(err); } });四、鉴权中间件登录后访问受保护接口需要我已登录的凭证function requireAuth(req, res, next) { if (!req.session.userId) { return res.status(401).json({ error: 未登录 }); } next(); } // 保护接口 app.use(/api/profile, requireAuth); app.use(/api/orders, requireAuth); // 公开接口 app.use(/api/auth/login, /* 不加 requireAuth */); app.use(/api/public, /* 不加 requireAuth */);4.1 加载当前用户每次请求加载用户信息避免在 req.user 上缓存过期数据async function loadUser(req, res, next) { if (!req.session.userId) return next(); try { const user await User.findByPk(req.session.userId, { attributes: [id, name, email, avatar], // 不取 password }); if (user) req.user user; next(); } catch (err) { next(err); } } app.use(loadUser); // 业务路由里直接用 router.get(/profile, (req, res) { if (!req.user) return res.status(401).json({ error: 未登录 }); res.json(req.user); });4.2 角色鉴权function requireRole(role) { return (req, res, next) { if (!req.user) return res.status(401).json({ error: 未登录 }); if (req.user.role ! role) { return res.status(403).json({ error: 权限不足 }); } next(); }; } router.delete(/users/:id, requireRole(admin), deleteUser);五、退出登录router.post(/logout, (req, res) { // 销毁 session req.session.destroy((err) { if (err) return next(err); res.clearCookie(connect.sid); // 清除 session cookie res.json({ ok: true }); }); });六、密码安全规范6.1 必须做的事规则理由用bcrypt哈希自动加盐 慢哈希至少 8 位太短会被秒破不限制字符集强密码规则反而让用户用Password1!不存明文数据库泄露 用户全完登录失败通用提示不泄露账号是否存在限流登录接口防暴力破解6.2 不要做的事❌ 用 MD5 / SHA1 哈希密码已被攻破❌ 自己加盐然后存 hash直接用 bcrypt❌ 在日志里记录密码❌ 通过 URL query 传密码❌ 把 token 存 LocalStorage防 XSS 偷七、常见漏洞漏洞攻击方式防护暴力破解反复试密码登录限流 验证码凭据填充用泄露密码批量试检测异常 IP / 异地登录会话固定攻击者预设 sessionId登录成功后重置 sessionId会话劫持XSS 偷 CookieHttpOnly SecureCSRF跨站请求SameSiteLax CSRF Token八、最佳实践场景推荐密码存储bcryptcost10-12会话方案Sessionexpress-session或 JWTCookie 属性HttpOnlySecureSameSiteLax失败提示通用邮箱或密码错误接口限流express-rate-limit日志脱敏不记密码、token退出req.session.destroy()res.clearCookie()九、小结登录流程验证请求体 → 查用户 → bcrypt 比对 → 设置会话 → 返回用户信息鉴权中间件requireAuth检查req.session.userId未登录返回 401角色鉴权requireRole(role)在 requireAuth 基础上再校验角色失败提示要通用“邮箱或密码错误”不泄露账号是否存在密码用 bcrypt 哈希Cookie 用 HttpOnly Secure SameSiteLaxsession 与 JWT 两种会话方案下两章分别讲
延伸阅读

更多相关文章

2026/10/21 3:02:57

微信小程序集成科大讯飞语音识别:音频处理与实时流式架构实战

简介:本资源是一套面向微信小程序开发者的科大讯飞语音识别集成实战方案,聚焦解决小程序端语音上传、PCM格式转换、音频降噪提取及实时语音转文字等核心痛点,适用于具备基础JavaScript与小程序开发能力的中初级开发者。压缩包共34个文件&…

2026/10/21 20:29:28

Python的Web框架“FastApi“常用的ORM框架

安装第三方库:"sqlalchemy" 让你用 Python 类和对象来操作数据库表和数据,把 SQL 语句翻译成 Python 代码。加"[asyncio] "确保 greenlet 被安装,让你能用 create_async_engine"aiomysql"负责真正的数据库网络…

2026/10/21 13:47:36

鲜花网站课程设计全攻略:从需求拆解到答辩避坑

简介:这是一份基于HTML5、CSS3与JavaScript的鲜花网站课程设计项目,主要面向计算机相关专业学生及前端入门开发者,用于完成网页设计类课程作业或积累仿真实战经验。项目不仅使用语义化标签搭建页面框架,借助Flex/Grid实现响应式布…

2026/10/23 3:43:49

电机驱动器通讯中断后失控?排查思路与保护策略全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/23 3:43:49

拟球形三维芯片架构:突破摩尔定律散热与互连瓶颈的新思路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/23 3:43:49

SPI与I2C协议详解:片间串行通信的取舍与调试实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/23 3:43:49

Windows 11 25H2官方镜像获取、启动盘制作与安装升级指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/23 3:38:49

macOS窗口置顶工具Topit使用指南:三步上手与避坑技巧

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/22 11:29:28

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/23 0:02:26

Verilog实现FPGA密码锁:矩阵键盘与状态机设计实战

说实话,这几年接触了不少想入门FPGA的朋友,如果你问哪个项目能一口气把Verilog的核心基本功串起来,我通常会推荐电子密码锁。这个项目看着不起眼,却把矩阵键盘扫描、按键消抖、状态机设计、动态显示刷新、外设控制这些数字逻辑里的…

2026/10/23 0:02:26

数据服务监控运维实战:从指标体系到告警治理与故障排查

周末凌晨两点,手机震了。第一反应是“数据服务挂了”。打开电脑看了下,果然,某张核心报表的数据产出时间已经超过SLA两小时,下游三个业务方连着发来问询。这种场景,做过大数据运维的人都不会陌生。数据服务的监控与运维…

2026/10/23 0:02:26

FreeRTOS任务通知实战详解:内核原理、API与避坑指南

裸机编程切到RTOS之后,任务之间的通信和同步永远是躲不开的坎。前面聊过队列、信号量、互斥锁、事件组,这次把FreeRTOS任务通知(Task Notification)单独拎出来讲透。原因很简单:任务通知是FreeRTOS里最容易用错、也最容…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑