token验证
主要面向刚接触鉴权的同学,用最 simple 的语言解释 Token(令牌)是什么、为什么要用、怎么用,帮助 you 了解并快速上手。
用一个比喻先理解「Token」
把 Token 想象成「门票」。用户第一次用账号密码换来一张门票(Token),以后进门就出示这张门票,服务端不会每次都问你账号密码,只要门票有效就让你进。门票可能有有效期、可以被收回(注销)或续签(刷新)。
基本概念(简单版)
- Token:服务端签发给客户端的一串字符串,代表用户身份。
- 无状态:服务器不存用户会话,所有判断靠 Token 本身或短期的服务器检查。
- JWT:一种常见格式,内容可读(不要放敏感信息),有签名防篡改。
流程:
- 用户在登录页输入用户名/密码并提交。
- 服务端验证成功后,生成 Token(可以是 JWT),返回给前端。
- 前端保存 Token(下面有存储建议),并在后续请求把 Token 放到请求头发送给服务端。
- 服务端校验 Token,校验通过则返回数据;不通过(例如过期)则返回 401,需要重新登录或刷新 Token。
下面把每一步用最小示例进行演示。
怎么存 Token(实用建议)
- 推荐(浏览器):把敏感的 Token 放到
HttpOnly的 Cookie,这样 JavaScript 不能直接读取,能减少 XSS 风险。 - 简单(但有风险):
localStorage/sessionStorage,方便单页应用使用,但容易被 XSS 读取,短期 Token 可以考虑。 - 无论哪种方式:一定要使用 HTTPS!
代码示例(最简单、可复制)
后端:Express + jsonwebtoken
先安装依赖:
npm init -y
npm install express jsonwebtoken body-parser
在 server.js 写入:
const express = require('express');
const jwt = require('jsonwebtoken');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
// 注意:实际项目中 SECRET 要保存在环境变量中
const ACCESS_SECRET = '替换为你自己的长随机字符串';
// 模拟登录接口
app.post('/login', (req, res) => {
const { username, password } = req.body;
// 这里只是演示:实际请用数据库验证
if (username === 'alice' && password === 'password') {
const accessToken = jwt.sign({ sub: 'alice' }, ACCESS_SECRET, { expiresIn: '15m' });
return res.json({ accessToken });
}
return res.status(401).json({ message: '用户名或密码错误' });
});
// 受保护的接口示例
function verifyAccessToken(req, res, next) {
const auth = req.headers.authorization;
const token = auth && auth.split(' ')[1];
if (!token) return res.status(401).json({ message: '缺少 token' });
try {
req.user = jwt.verify(token, ACCESS_SECRET);
next();
} catch (err) {
return res.status(401).json({ message: '无效或已过期的 token' });
}
}
app.get('/profile', verifyAccessToken, (req, res) => {
res.json({ message: `欢迎 ${req.user.sub}` });
});
app.listen(3000, () => console.log('Server on http://localhost:3000'));
测试登录和访问(使用 curl):
# 登录拿 token
curl -s -X POST http://localhost:3000/login -H "Content-Type: application/json" -d '{"username":"alice","password":"password"}'
# 假设拿到的 token 是 ABC,访问受保护接口
curl -H "Authorization: Bearer ABC" http://localhost:3000/profile
(实际拿到的 token 很长,替换 ABC 为响应中的 accessToken)
每一行示例代码都很短,读懂要点:jwt.sign(payload, secret, options) 生成 token,jwt.verify(token, secret) 验证并解码。
常见进阶:access token 与 refresh token
- access token(短期门票):有效期短,例如 15 分钟,用来频繁访问接口。
- refresh token(长期凭证):有效期长,例如 7 天,用来在 access token 过期后换一张新的 access token。刷新流程要非常小心:刷新接口需要保护(绑定客户端、限速、检测异常)。
流程示意:客户端保存两个东西,access(短)和 refresh(长)。当短的过期,用长的换新的短的。
注销(登出)怎么做?
- 如果只是前端删除 token:用户在当前设备离线有效,但别人持有旧 token 仍可访问。
- 要强制立即失效:需要服务端维护短期黑名单(例如 Redis),把被撤销的 token 加入黑名单并检查。这会让鉴权变成“部分有状态”。
常见问题
- Q:JWT 是不是加密的?
A:默认是签名(可以验证是否被篡改),payload 可以被解码并看到,不是加密。需要加密内容请另外处理。 - Q:token 放 localStorage安全吗?
A:localStorage 容易被 XSS 读取,不建议存长期权限敏感的 token。更安全的方式是 HttpOnly Cookie。 - Q:token 被偷了怎么办?
A:尽快缩短 access token 有效期,使用 refresh token + 旋转策略,并在发现异常时把 refresh token 列入黑名单。
so you can
- 运行上面的
server.js示例并用curl调试,观察返回的 token。 - 把 token 放入
Authorization头,访问受保护接口,理解 401 的含义。 - 学习如何在前端用 Axios 自动带上 token,并实现简单的刷新逻辑。
参考资料
- https://jwt.io/
- RFC 7519 (JSON Web Token)

浙公网安备 33010602011771号