# JWT 鉴权

URL: https://caijiao.org/hono/04-middleware/02-jwt-auth
Source: docs/hono/04-middleware/02-jwt-auth.md
Description: 学习 Hono JWT 中间件的基本用法、Bearer Token 校验、保护路由和读取 payload。

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 !== 'admin@example.com' || 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。
