Bearer 中间件
用于 Vafast 的中间件,用于获取 Bearer 令牌。
安装
通过以下命令安装:
bash
npm install @vafast/bearer基本用法
typescript
import { Server, defineRoute, defineRoutes } from 'vafast'
import { bearer } from '@vafast/bearer'
// 定义路由处理器
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/',
handler: () => {
return { message: 'Bearer Token API' }
}
}),
defineRoute({
method: 'GET',
path: '/sign',
middleware: [bearer()],
handler: ({ bearer: bearerToken }) => {
// 访问 bearer 令牌,具有完整的类型安全
if (!bearerToken) {
return {
error: 'Unauthorized',
message: 'Bearer token required'
}
}
return { token: bearerToken }
}
})
])
// 创建服务器
const server = new Server(routes)
// 导出 fetch 函数
export default { fetch: server.fetch }新框架用法说明:
- 使用
defineRoute定义路由- Bearer 中间件通过
middleware字段应用- Handler 自动获得
bearer参数的类型推断
配置选项
BearerOptions
typescript
interface BearerOptions {
extract: {
/**
* 确定从请求体中提取令牌的字段名
* @default 'access_token'
*/
body?: string
/**
* 确定从查询参数中提取令牌的字段名
* @default 'access_token'
*/
query?: string
/**
* 确定哪种类型的认证应该是 Bearer 令牌
* @default 'Bearer'
*/
header?: string
}
}令牌提取策略
该中间件按照以下优先级从请求中提取 Bearer 令牌:
- Authorization 头部 - 默认格式:
Bearer <token> - 查询参数 - 默认参数名:
access_token - 请求体 - 默认字段名:
access_token(仅非 GET 请求)
使用模式
1. 基本认证检查
typescript
import { defineRoute, defineRoutes } from 'vafast'
import { bearer } from '@vafast/bearer'
import { err } from 'vafast'
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/protected',
middleware: [bearer()],
handler: ({ bearer: bearerToken }) => {
if (!bearerToken) {
throw err.unauthorized('Bearer token required')
}
// 验证令牌逻辑
if (!isValidToken(bearerToken)) {
throw err.unauthorized('Invalid token')
}
return { message: 'Access granted', user: getUserFromToken(bearerToken) }
}
})
])2. 自定义令牌提取
typescript
import { defineRoute, defineRoutes } from 'vafast'
import { bearer } from '@vafast/bearer'
// 自定义令牌提取配置
const customBearer = bearer({
extract: {
body: 'token', // 从请求体的 'token' 字段提取
query: 'auth_token', // 从查询参数的 'auth_token' 提取
header: 'Token' // 从 'Token' 头部提取
}
})
const routes = defineRoutes([
defineRoute({
method: 'POST',
path: '/login',
middleware: [customBearer],
handler: ({ bearer: bearerToken }) => {
// 现在可以从自定义字段中获取令牌
return { receivedToken: bearerToken }
}
})
])
const server = new Server(routes)
export default {
fetch: server.fetch
}3. 中间件链式应用
typescript
import { defineRoute, defineRoutes } from 'vafast'
import { bearer } from '@vafast/bearer'
import { cors } from '@vafast/cors'
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/api/user',
middleware: [bearer()],
handler: ({ bearer: bearerToken }) => {
return { user: getUserProfile(bearerToken) }
}
})
])
const server = new Server(routes)
// 使用 server.useGlobalMiddleware() 应用全局中间件(推荐)
server.useGlobalMiddleware(cors())
server.useGlobalMiddleware(bearer())
export default {
fetch: server.fetch
}4. 条件中间件应用
typescript
import { bearer, createTypedHandler } from '@vafast/bearer'
const routes = [
defineRoute({
method: 'GET',
path: '/public',
handler: () => {
return { message: 'Public endpoint' }
}
}),
defineRoute({
method: 'GET',
path: '/private',
middleware: [bearer()],
handler: ({ bearer: bearerToken }) => {
return { message: 'Private endpoint', token: bearerToken }
}
})
])
const server = new Server(routes)
// 方式一:使用 server.useGlobalMiddleware()(推荐,适用于所有路由)
server.useGlobalMiddleware(bearer())
export default {
fetch: server.fetch
}
// 方式二:条件应用(高级用法,仅在特殊场景下使用)
// export default {
// fetch: (req: Request) => {
// const url = new URL(req.url)
//
// // 只为私有端点应用 bearer 中间件
// if (url.pathname.startsWith('/private')) {
// return bearer()(req, () => server.fetch(req))
// }
//
// return server.fetch(req)
// }
// }完整示例
typescript
import { Server, defineRoute, defineRoutes } from 'vafast'
import { bearer } from '@vafast/bearer'
// 模拟用户验证函数
const validateToken = (token: string): boolean => {
return token === 'valid-token-123'
}
const getUserFromToken = (token: string) => {
return { id: 1, username: 'john_doe', email: 'john@example.com' }
}
// 定义路由
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/',
handler: () => {
return { message: 'Bearer Token Authentication API' }
}
}),
defineRoute({
method: 'POST',
path: '/login',
handler: async (req: Request) => {
const body = await req.json()
const { username, password } = body
// 简单的登录逻辑
if (username === 'admin' && password === 'password') {
return {
message: 'Login successful',
token: 'valid-token-123'
}
}
return {
status: 401,
error: 'Invalid credentials'
}
}
}),
defineRoute({
method: 'GET',
path: '/profile',
middleware: [bearer()],
handler: ({ bearer: bearerToken }) => {
if (!bearerToken) {
return {
status: 401,
error: 'Unauthorized',
message: 'Bearer token required'
}
}
if (!validateToken(bearerToken)) {
return {
status: 401,
error: 'Unauthorized',
message: 'Invalid token'
}
}
const user = getUserFromToken(bearerToken)
return {
message: 'Profile retrieved successfully',
user
}
}
}),
defineRoute({
method: 'GET',
path: '/admin',
middleware: [bearer()],
handler: ({ bearer: bearerToken }) => {
if (!bearerToken) {
return {
status: 401,
error: 'Unauthorized'
}
}
// 检查管理员权限
if (bearerToken !== 'admin-token-456') {
return {
status: 403,
error: 'Forbidden',
message: 'Admin access required'
}
}
return {
message: 'Admin panel accessed',
adminData: { users: 100, systemStatus: 'healthy' }
}
}
})
])
// 创建服务器
const server = new Server(routes)
// 导出 fetch 函数
export default { fetch: server.fetch }console.log('Bearer Token API 服务器启动成功!') console.log('登录端点: POST /login') console.log('👤 个人资料: GET /profile (需要 Bearer 令牌)') console.log('管理面板: GET /admin (需要管理员令牌)')
## 测试示例
```typescript
import { describe, expect, it } from 'bun:test'
describe('Bearer Token API', () => {
it('should require bearer token for protected routes', async () => {
const res = await app.fetch(new Request('http://localhost/profile'))
const data = await res.json()
expect(res.status).toBe(401)
expect(data.error).toBe('Unauthorized')
})
it('should accept valid bearer token', async () => {
const res = await app.fetch(new Request('http://localhost/profile', {
headers: {
'Authorization': 'Bearer valid-token-123'
}
}))
const data = await res.json()
expect(res.status).toBe(200)
expect(data.message).toBe('Profile retrieved successfully')
expect(data.user).toBeDefined()
})
it('should extract token from query parameters', async () => {
const res = await app.fetch(new Request('http://localhost/profile?access_token=valid-token-123'))
const data = await res.json()
expect(res.status).toBe(200)
expect(data.user).toBeDefined()
})
})特性
- ✅ RFC6750 兼容: 完全符合 Bearer 令牌规范
- ✅ 多种提取方式: 支持头部、查询参数和请求体提取
- ✅ 类型安全: 使用
createTypedHandler提供完整的类型安全 - ✅ 灵活配置: 可自定义令牌提取字段和头部名称
- ✅ 中间件集成: 无缝集成到 Vafast 应用
- ✅ 高性能: 轻量级实现,最小化性能开销
注意事项
令牌验证: 该中间件只负责提取令牌,不处理验证逻辑。开发者需要自己实现令牌验证。
安全性: 在生产环境中,确保使用 HTTPS 传输令牌,并实现适当的令牌过期和刷新机制。
错误处理: 建议在令牌无效时返回适当的 HTTP 状态码和错误信息。
中间件顺序: Bearer 中间件应该在路由处理之前应用,以确保令牌在处理器中可用。