0Pricing
Vue Academy · 课时

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 反馈 — 无需本地设置。

此课程中的所有课时

  1. 面向 Vue SPA 的 Fastify 后端
  2. JWT 认证:登录与刷新
  3. 使用 Axios 拦截器调用需认证的 API
  4. 将全栈 Vue 应用部署到生产环境
← 返回 Vue Academy