教程 hono tutorial

JWT 鉴权

Hono 内置 JWT 中间件,可以验证 Bearer Token 并保护指定路由。

基本用法

ts
import { Hono } from 'hono'
import { jwt } from 'hono/jwt'

const app = new Hono()

app.use(
  '/api/private/*',
  jwt({
    secret: 'my-secret',
  }),
)

app.get('/api/private/me', (c) => {
  const payload = c.get('jwtPayload')
  return c.json({ payload })
})

客户端请求:

bash
curl http://localhost:3000/api/private/me \
  -H "Authorization: Bearer <token>"

不要硬编码密钥

密钥应该来自环境变量或平台 Secret:

ts
const secret = process.env.JWT_SECRET

if (!secret) {
  throw new Error('JWT_SECRET is required')
}

app.use('/api/private/*', jwt({ secret }))

Cloudflare Workers 中可以从 c.env 读取,但中间件注册时拿不到单个请求的 c.env。这种情况下可以写自定义中间件或使用支持动态配置的封装方式。

登录后签发 Token

可以使用 hono/jwt 的 sign:

ts
import { sign } from 'hono/jwt'

app.post('/api/login', async (c) => {
  const { email, password } = await c.req.json<{
    email: string
    password: string
  }>()

  if (email !== '[email protected]' || password !== 'secret') {
    return c.json({ message: 'Invalid credentials' }, 401)
  }

  const token = await sign(
    {
      sub: 'user_1',
      role: 'admin',
      exp: Math.floor(Date.now() / 1000) + 60 * 60,
    },
    'my-secret',
  )

  return c.json({ token })
})

示例中使用明文账号密码只是为了说明流程。真实项目必须使用数据库和密码哈希。

保护路由的组织方式

ts
const api = new Hono()

api.get('/public', (c) => c.json({ ok: true }))

api.use('/private/*', jwt({ secret: 'my-secret' }))
api.get('/private/me', (c) => c.json(c.get('jwtPayload')))

app.route('/api', api)

把公开路由和私有路由的边界写清楚,比在每个处理函数里手动判断更可靠。

安全建议

  • JWT 密钥必须足够随机,并通过 Secret 管理。
  • 设置 exp,避免永不过期 Token。
  • 不要在 JWT payload 中放密码、身份证号、访问密钥等敏感信息。
  • 高风险业务要设计吊销机制,例如 token version、黑名单或短期 access token 加 refresh token。