JWT 认证:登录与刷新
访问令牌与刷新令牌流程、httpOnly Cookie,以及使用拦截器静默刷新
JWT 认证:登录与刷新 是 CoddyKit 上的免费 Vue Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Vue Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Vue Academy 课程共包含 4 节课。
访问 token 与刷新 token 模型
稳健的 JWT 方案使用两种 token:短期有效的访问 token(几分钟),随每个 API 请求发送;以及长期有效的刷新 token(几天),仅用于签发新的访问 token。如果访问 token 泄露,这种方式可以缩小暴露范围。
注册 JWT 插件
使用 Fastify 时,注册 @fastify/jwt 并提供一个强密钥。它会向应用对象和请求对象添加签名与验证辅助方法。
import jwt from '@fastify/jwt'
await app.register(jwt, {
secret: process.env.JWT_SECRET
})登录路由
POST /auth/login 会验证凭据,然后签发两个 token。切勿存储明文密码——请与哈希值进行比对(bcrypt/argon2)。
app.post('/auth/login', async (req, reply) => {
const { email, password } = req.body
const user = await findUser(email)
if (!user || !(await verifyHash(password, user.hash))) {
return reply.code(401).send({ error: 'Invalid credentials' })
}
// ... sign tokens (next scene)
})签发访问 token
使用用户 ID 和最少的声明签发一个短期有效的访问 token。请将过期时间设置得较短(例如 15 分钟)。
const accessToken = app.jwt.sign(
{ sub: user.id, role: user.role },
{ expiresIn: '15m' }
)签发刷新 token
使用独立的载荷标记(或单独的密钥)签发一个长期有效的刷新 token。它只能用于刷新端点。
const refreshToken = app.jwt.sign(
{ sub: user.id, type: 'refresh' },
{ expiresIn: '7d' }
)httpOnly Cookie 中的刷新 token
将刷新 token 存储在带有 httpOnly、SameSite 和安全属性的 Cookie 中。JavaScript 无法读取它(从而减轻 XSS 盗取的风险),浏览器会自动将它发送到刷新端点。
reply.setCookie('refreshToken', refreshToken, {
httpOnly: true,
sameSite: 'strict',
secure: true, // HTTPS only
path: '/auth/refresh',
maxAge: 60 * 60 * 24 * 7
})在请求体中返回访问 token
访问 token 会在 JSON 响应体中返回。Vue 应用会将它保存在内存中(而不是 localStorage),并将其附加到 API 请求上。刷新 token 永远不会出现在请求体中。
return reply.send({
accessToken,
user: { id: user.id, name: user.name }
})
// refreshToken is only in the httpOnly cookie为什么不将访问 token 存储在 localStorage 中
任何脚本都可以读取 localStorage,因此其中的 token 可能被 XSS 漏洞窃取。将访问 token 保存在 JavaScript 内存中,并将刷新 token 保存在 httpOnly Cookie 中,可以降低 XSS 的影响范围。
刷新路由
POST /auth/refresh 会从 Cookie 中读取刷新 token,验证它,然后签发新的访问 token。新访问 token 会在请求体中返回。
app.post('/auth/refresh', async (req, reply) => {
const token = req.cookies.refreshToken
if (!token) return reply.code(401).send()
try {
const payload = app.jwt.verify(token)
const accessToken = app.jwt.sign(
{ sub: payload.sub }, { expiresIn: '15m' }
)
return reply.send({ accessToken })
} catch {
return reply.code(401).send({ error: 'Invalid refresh' })
}
})保护路由
添加一个 preHandler,验证来自 Authorization 请求头的访问 token。@fastify/jwt 的 request.jwtVerify() 遇到无效或过期的 token 时会抛出异常,并返回 401。
app.get('/api/me', {
preHandler: async (req, reply) => {
try { await req.jwtVerify() }
catch { reply.code(401).send({ error: 'Unauthorized' }) }
}
}, async (req) => getProfile(req.user.sub))退出登录:清除 Cookie
退出登录时会清除刷新 Cookie,使其无法再签发访问 token。为了提供更强的保障,还可以在服务器端跟踪并撤销刷新 token(使用拒绝列表或轮换机制)。
app.post('/auth/logout', async (req, reply) => {
reply.clearCookie('refreshToken', { path: '/auth/refresh' })
return reply.send({ ok: true })
})快速检查
测试您对 JWT 身份验证的理解。
回顾
您已经学会了 JWT 登录和刷新机制:
- 短期有效的访问 token加上长期有效的刷新 token
POST /auth/login会验证凭据并签发两个 token- 刷新 token 放在 httpOnly SameSite 安全 Cookie 中
- 访问 token 在请求体中返回,并保存在 JavaScript 内存中
POST /auth/refresh使用 Cookie 签发新的访问 token
常见问题解答
「JWT 认证:登录与刷新」课时是免费的吗?
是的 — 「JWT 认证:登录与刷新」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Vue Academy 课程的其余内容,请升级到 CoddyKit PRO。 Vue Academy 课程共包含 4 节课。
「JWT 认证:登录与刷新」这节课中我会学到什么?
访问令牌与刷新令牌流程、httpOnly Cookie,以及使用拦截器静默刷新 你通过在浏览器中直接运行的动手代码来练习 Vue Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Vue Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Vue Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「JWT 认证:登录与刷新」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Vue Academy 课中编写并运行代码吗?
能。每节 Vue Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。