✍ 前言:登录不是登录,是一场身份的较量
还记得你第一次做登录功能吗?是不是写个 /login,用户名密码验证完,直接 res.send("登录成功!") 就结束了?
但问题来了:
- 登录之后,怎么知道后续请求是你发的?
- 每次请求都要查数据库?太累了吧?
- Session 你听过,JWT 呢?好像高级点?
今天,就来带你走一波 JWT 登录认证的实战路线,让你从“登录小白”进阶为“身份掌控者”!
🧠 什么是 JWT?
JWT,全称 JSON Web Token,是一种跨服务的身份令牌机制。
它的核心目标只有一个:
✅ 用户登录之后,给他一个“身份令牌”,以后每次请求拿这个令牌就行,无须每次都查数据库,也不需要维护复杂的 Session。
🧱 JWT 的结构是啥?
JWT 长得像一段超长字符串,比如下面这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VySWQiOjEyMywidXNlcm5hbWUiOiJhamF4IiwiaWF0IjoxNjg1MDA2NDAwfQ.
W5I5dFTFG9SGzSNRkZz_PdD3fgz0Z3xLpoHDZq9aXGM
被点(.)分成三段,分别代表:
| 部分 | 含义 | 示例内容 |
|---|---|---|
| Header | 算法和类型 | {"alg":"HS256","typ":"JWT"} |
| Payload | 数据内容(比如 userId) | {"userId":123,"username":"ajax"} |
| Signature | 签名(加密串) | 防篡改的验证串 |
⚠ 注意:Payload 是 明文 Base64 编码,不要写敏感信息!
🚀 使用流程(通俗易懂版)
🧑💻 后端的套路:
-
用户发起登录(POST /login)
-
后端验证账号密码正确
-
使用 secret 生成 JWT:
const token = jwt.sign({ userId: 123 }, 'secret', { expiresIn: '2h' }) -
把
token发给前端
🖥️ 前端的操作:
-
登录成功后拿到
token -
保存到
localStorage(或 cookie) -
后续请求中加上:
fetch('/api/user', { headers: { 'Authorization': 'Bearer ' + token } })
🔍 后端怎么验证?
const token = req.headers.authorization?.split(' ')[1]
const decoded = jwt.verify(token, 'secret')
console.log(decoded) // => { userId: 123, iat: xxx, exp: xxx }
🧪 实战演练:Node + Express + JWT 登录系统
🎯 安装依赖
npm install express jsonwebtoken body-parser
🧩 示例代码
const express = require('express')
const jwt = require('jsonwebtoken')
const bodyParser = require('body-parser')
const app = express()
const SECRET = 'my-secret'
app.use(bodyParser.json())
// 模拟用户登录
app.post('/login', (req, res) => {
const { username, password } = req.body
if (username === 'admin' && password === '123456') {
const token = jwt.sign({ username }, SECRET, { expiresIn: '1h' })
res.json({ token })
} else {
res.status(401).json({ message: '登录失败' })
}
})
// 授权接口
app.get('/profile', (req, res) => {
const auth = req.headers.authorization
if (!auth) return res.status(401).json({ message: '缺少token' })
const token = auth.split(' ')[1]
try {
const decoded = jwt.verify(token, SECRET)
res.json({ msg: '成功访问!', user: decoded })
} catch (err) {
res.status(403).json({ msg: 'Token无效或过期' })
}
})
app.listen(3000, () => {
console.log('http://localhost:3000 启动成功')
})
🍪 JWT 和 Cookie 的正面对决:谁更适合我?
很多刚接触前后端认证的同学都会问:
❓“JWT 和 Cookie 是不是一回事?”
❓“我项目该用哪个?”
回答:不是一回事!但可以搭配使用。
我们来看下它们的区别和用途:
| 对比维度 | JWT | Cookie |
|---|---|---|
| 定义 | 一种令牌规范 | 浏览器内建的存储机制 |
| 储存位置 | 可存 localStorage、cookie 等 | 浏览器自动维护 |
| 用途 | 身份令牌(认证、权限控制) | 存储小数据(sessionId、偏好设置) |
| 大小限制 | ~7kb(Base64) | 每个 cookie 限 ~4kb |
| 跨域限制 | 默认不带 cookie,需手动设置 | 跨域默认不发送,需要配置 withCredentials |
| 安全性 | 容易被 XSS 获取(如果存在 localStorage) | 易受 CSRF 攻击,需搭配 SameSite+HttpOnly |
| 服务端压力 | 无状态,服务端无存储压力 | 需要 session 存储,服务端开销更大 |
✅ 合理搭配最佳实践:
| 模式 | 实现方案 |
|---|---|
| Token 存在 localStorage | 易开发,适合移动端 / 简单项目 |
| Token 存在 HttpOnly Cookie | 安全性更高,适合生产环境 |
| Cookie 中放 SessionID,后端维护状态 | 传统 Web 模式,适合老项目或服务端渲染 |
🧠 总结升级版:JWT ≠ Cookie,它们可以并肩作战!
JWT 更像是一个“内容丰富的身份证”,而 Cookie 更像是“操作系统的口袋”。你可以选择:
- 开发速度优先 →
JWT + localStorage - 安全性优先 →
JWT + HttpOnly Cookie - SSR 项目 / 老系统 →
Cookie + Session
🔥 实际开发中,你得注意的“坑”
-
Token 太大了?
不要把用户资料全写进去,只放最小的userId或权限等级 -
Token 过期怎么办?
用expiresIn设置时间,配合刷新令牌(Refresh Token)策略更稳妥 -
退出登录怎么处理?
JWT 没有内建注销机制,常见方式是:- 设置黑名单(Redis 存储无效 token)
- 缩短有效期 + Refresh Token 控制生命周期
-
要不要放在 localStorage?
localStorage: 简单易用但不防 XSScookie + HttpOnly: 安全性更高(推荐)
🧭 JWT 在前端项目中的应用场景
- React / Vue 项目用户登录认证
- 后台管理系统权限控制
- App 小程序等移动端请求授权
- 与后端分离的 API 接口认证
🧾 总结
JWT 是一把钥匙,解决了前后端分离后的“我是谁”问题:
✅ 轻量、无状态
✅ 易于分布式部署
✅ 开发简单,上手快
🧑🎓 最后一句话总结
以前是“谁登录谁知道”,
现在是“你拿 token,大家都知道你是谁”。
JWT,就像是现代前端江湖中的一枚通行令牌,在微服务横行、前后端分离的大环境下,它以简洁而优雅的方式,解决了“你是谁”与“你是否有权”的千古难题。它无须依赖服务端状态,却能守住数据边界的底线;它可以轻巧存于 localStorage,也可以悄然藏身于 HttpOnly Cookie,既能追求速度,也能坚守安全。从身份认证到权限控制,从请求头到签名算法,这不仅是一次技术的实践,更是开发者与系统信任机制之间的一次深度握手。学会 JWT,不只是为了实现一个登录功能,而是你构建安全、高效、可扩展应用体系的第一步。
如果你觉得文章有帮助,欢迎点赞 + 收藏 + 评论~
你的三连,是我写作的最大动力 🧡