@huyooo/hono-middlewares
v0.1.18
Published
A collection of useful Hono middlewares
Readme
⚡️ Hono Middlewares
一个为 Hono 框架提供常用中间件集合的库,包含日志、认证、验证、错误处理等常用功能。
✨ 特性
- 🚀 开箱即用: 提供常用的中间件集合,无需额外配置
- 🔧 配置驱动: 通过统一的配置对象管理所有中间件
- 🛡️ 类型安全: 完整的 TypeScript 支持,智能类型提示
- 📦 模块化: 可以独立使用各个中间件,也可以使用综合包
- 🎯 标准化错误: 重新封装的中间件(bodyLimit、timeout、csrf、ipRestriction、rateLimiter)提供统一的错误格式
- 🎯 生产就绪: 包含安全、性能、监控等生产环境必需功能
- ⚡️ 高性能: 基于 Hono 的高性能中间件架构
- 🔒 安全优先: 内置 CORS、CSRF、安全头部等安全功能
- 📊 监控友好: 内置请求 ID、性能监控、结构化日志
📦 安装
# 安装 hono-middlewares
npm install @huyooo/hono-middlewares
# 安装 peer dependency
npm install hono🚀 快速开始
💡 提示: 我们重新封装了
bodyLimit、timeout、csrf、ipRestriction和rateLimiter中间件,它们现在都提供标准化的错误格式,与我们的错误处理系统完全兼容。
使用综合中间件包(推荐)
import { Hono } from 'hono'
import { middlewareBundle } from '@huyooo/hono-middlewares'
const app = new Hono()
// 使用默认配置
app.use('*', middlewareBundle())
// 或者自定义配置
app.use('*', middlewareBundle({
logging: {
service: 'my-api-service',
enablePrettyPrint: false,
},
cors: {
origin: ['https://yourdomain.com'],
credentials: true,
},
rateLimit: {
limit: 1000,
},
}))
app.get('/', (c) => c.json({ message: 'Hello World!' }))环境区分配置(推荐)
import { Hono } from "hono";
import { middlewareBundle } from "@huyooo/hono-middlewares";
const app = new Hono();
const isDev = process.env.NODE_ENV === 'development';
const isProd = process.env.NODE_ENV === 'production';
app.use("*", middlewareBundle({
logging: {
service: "my-api-service",
enablePrettyPrint: isDev,
},
cors: {
origin: isProd ? ['https://yourdomain.com'] : '*',
credentials: isProd,
// 其他选项使用默认值:allowMethods, allowHeaders, exposeHeaders, maxAge
},
rateLimit: {
limit: isProd ? 1000 : 10000,
},
prettyJSON: { enabled: isDev },
timing: { enabled: isDev },
csrf: { enabled: isProd },
}));使用独立中间件
import { Hono } from 'hono'
// 从主包导入核心中间件(不包含官方中间件)
import {
auth,
schemaValidator,
t,
errorHandler,
rateLimiter,
middlewareBundle
} from '@huyooo/hono-middlewares'
// 从 core 包导入官方中间件
import {
cors,
secureHeaders,
timing,
requestId,
compress,
bodyLimit,
timeout,
appendTrailingSlash
} from '@huyooo/hono-middlewares/core'
const app = new Hono()
// 错误处理 app.use('*', errorHandler())
// CORS 配置 app.use('*', cors({ origin: ['https://yourdomain.com'], credentials: true, }))
// 安全头部 app.use('*', secureHeaders())
// 性能监控 app.use('', timing()) app.use('', requestId())
// 压缩响应 app.use('*', compress())
// 请求体大小限制 app.use('*', bodyLimit({ maxSize: 1024 * 1024, // 1MB }))
// 请求超时 app.use('*', timeout({ timeout: 5000, // 5秒 }))
// 尾部斜杠处理 app.use('*', appendTrailingSlash())
// 速率限制 app.use('*', rateLimiter({ windowMs: 15 * 60 * 1000, // 15分钟 limit: 100, // 限制100个请求 }))
// 认证中间件 app.get('/protected', auth(), (c) => { const userInfo = c.get('userInfo') return c.json({ message: 'Protected route', userInfo }) })
// API Key 认证中间件 app.get('/api/protected', apiKeyAuth(), (c) => { const apiKeyInfo = c.get('apiKeyInfo') const userInfo = c.get('userInfo') return c.json({ message: 'API Key protected route', apiKeyInfo, userInfo }) })
// 条件认证中间件 app.use('/api/*', conditionalAuth()) app.get('/api/data', (c) => { // 根据认证方式自动选择 API Key 或 JWT 认证 const apiKeyInfo = c.get('apiKeyInfo') const userInfo = c.get('userInfo') return c.json({ message: 'Conditionally authenticated', apiKeyInfo, userInfo }) })
// 参数验证 const userSchema = t.Object({ name: t.String(), email: t.String({ format: 'email' }), age: t.Number({ minimum: 18 }) })
app.post('/users', schemaValidator('json', userSchema), (c) => { const data = c.req.valid('json') return c.json({ message: 'User created', data }) })
## 📚 可用中间件
### 核心中间件
| 中间件 | 描述 | 导入方式 |
|--------|------|----------|
| `auth` | JWT 认证中间件 | `import { auth } from '@huyooo/hono-middlewares'` |
| `apiKeyAuth` | API Key 认证中间件 | `import { apiKeyAuth } from '@huyooo/hono-middlewares'` |
| `conditionalAuth` | 条件认证中间件 | `import { conditionalAuth } from '@huyooo/hono-middlewares'` |
| `pinoLogger` | Pino 日志中间件 | `import { pinoLogger } from '@huyooo/hono-middlewares'` |
| `requestLogger` | 请求日志中间件 | `import { requestLogger } from '@huyooo/hono-middlewares'` |
| `schemaValidator` | 参数验证中间件 | `import { schemaValidator, t } from '@huyooo/hono-middlewares'` |
| `errorHandler` | 错误处理中间件 | `import { errorHandler } from '@huyooo/hono-middlewares'` |
### Hono 官方中间件
| 中间件 | 描述 | 导入方式 |
|--------|------|----------|
| `prettyJSON` | JSON 美化输出 | `import { prettyJSON } from '@huyooo/hono-middlewares/core'` |
| `cors` | CORS 跨域支持 | `import { cors } from '@huyooo/hono-middlewares/core'` |
| `secureHeaders` | 安全头部设置 | `import { secureHeaders } from '@huyooo/hono-middlewares/core'` |
| `csrf` | CSRF 保护 | `import { csrf } from '@huyooo/hono-middlewares/core'` |
| `logger` | 基础日志中间件 | `import { logger } from '@huyooo/hono-middlewares/core'` |
| `timing` | 性能监控 | `import { timing } from '@huyooo/hono-middlewares/core'` |
| `requestId` | 请求 ID 生成 | `import { requestId } from '@huyooo/hono-middlewares/core'` |
| `compress` | 响应压缩 | `import { compress } from '@huyooo/hono-middlewares/core'` |
| `bodyLimit` | 请求体大小限制(标准化错误格式) | `import { bodyLimit } from '@huyooo/hono-middlewares/core'` |
| `timeout` | 请求超时控制(标准化错误格式) | `import { timeout } from '@huyooo/hono-middlewares/core'` |
| `csrf` | CSRF 保护(标准化错误格式) | `import { csrf } from '@huyooo/hono-middlewares/core'` |
| `ipRestriction` | IP 访问限制(标准化错误格式) | `import { ipRestriction } from '@huyooo/hono-middlewares/core'` |
| `appendTrailingSlash` | 添加尾部斜杠 | `import { appendTrailingSlash } from '@huyooo/hono-middlewares/core'` |
| `trimTrailingSlash` | 移除尾部斜杠 | `import { trimTrailingSlash } from '@huyooo/hono-middlewares/core'` |
| `ipRestriction` | IP 访问限制 | `import { ipRestriction } from '@huyooo/hono-middlewares/core'` |
### 第三方中间件
| 中间件 | 描述 | 导入方式 |
|--------|------|----------|
| `rateLimiter` | 速率限制 | `import { rateLimiter } from '@huyooo/hono-middlewares'` |
## 🔧 配置说明
### middlewareBundle 默认配置
为了提供更好的开箱即用体验和避免常见的兼容性问题,我们对默认配置进行了优化:
```typescript
const defaultConfig = {
// 日志配置 - 默认启用
logging: {
enabled: true,
service: '@huyooo/hono-middlewares',
enablePrettyPrint: false,
},
// CORS 配置 - 默认启用,允许所有来源
cors: {
enabled: true,
origin: '*',
allowMethods: ['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH', 'OPTIONS'],
allowHeaders: [],
exposeHeaders: [],
credentials: undefined,
maxAge: undefined,
},
// 安全头部 - 默认关闭,避免与 CORS 冲突
secureHeaders: {
enabled: false,
},
// 性能监控 - 默认启用
timing: {
enabled: true,
},
requestId: {
enabled: true,
},
// 速率限制 - 默认启用
rateLimit: {
enabled: true,
limit: 100,
windowMs: 15 * 60 * 1000,
},
// 压缩 - 默认关闭,避免 CORS 问题和其他兼容性问题
compress: {
enabled: false,
encoding: 'gzip',
},
// 其他中间件 - 默认关闭
csrf: { enabled: false },
bodyLimit: { enabled: false },
ipRestriction: { enabled: false },
timeout: { enabled: false },
trailingSlash: { enabled: false },
errorHandling: { enabled: true },
prettyJSON: { enabled: false },
}重要变更说明
🔧 默认配置优化
安全头部默认关闭 (
secureHeaders.enabled: false)- 原因: 避免与 CORS 的
origin: '*'配置冲突 - 影响: 生产环境需要手动启用安全头部
- 建议: 生产环境建议启用并配置具体的安全策略
- 原因: 避免与 CORS 的
压缩默认关闭 (
compress.enabled: false)- 原因: 避免与 CORS 处理和其他兼容性问题
- 影响: 响应不会被自动压缩
- 建议: 如需压缩,可手动启用或使用反向代理处理
CORS 默认允许所有来源 (
cors.origin: '*')- 原因: 提供开箱即用的跨域支持
- 影响: 开发环境友好,但生产环境需要配置具体域名
- 建议: 生产环境必须设置具体的
origin值
🎯 推荐配置
开发环境:
app.use('*', middlewareBundle({
logging: {
service: 'my-api-dev',
enablePrettyPrint: true,
},
cors: {
origin: '*', // 开发环境允许所有来源
},
prettyJSON: { enabled: true },
timing: { enabled: true },
}))生产环境:
app.use('*', middlewareBundle({
logging: {
service: 'my-api-prod',
enablePrettyPrint: false,
},
cors: {
origin: ['https://yourdomain.com'], // 生产环境指定具体域名
credentials: true,
},
secureHeaders: { enabled: true }, // 生产环境启用安全头部
compress: { enabled: true }, // 生产环境启用压缩
csrf: { enabled: true }, // 生产环境启用 CSRF 保护
rateLimit: {
limit: 1000, // 生产环境更严格的限制
},
}))middlewareBundle 配置
import { middlewareBundle, type MiddlewareBundleConfig } from '@huyooo/hono-middlewares'
const config: MiddlewareBundleConfig = {
// 日志配置
logging: {
enabled: true,
service: 'my-api',
enablePrettyPrint: false,
},
// CORS 配置
cors: {
enabled: true,
origin: ['https://yourdomain.com'],
credentials: true,
},
// 安全头部
secureHeaders: {
enabled: true,
},
// 性能监控
timing: {
enabled: true,
},
requestId: {
enabled: true,
},
// 速率限制
rateLimit: {
enabled: true,
limit: 1000,
windowMs: 15 * 60 * 1000,
},
// IP 限制
ipRestriction: {
enabled: true,
getConnInfo: getConnInfo, // 必须提供,根据运行环境选择
denyList: ["192.168.1.100", "10.0.0.0/8"],
allowList: ["127.0.0.1", "::1", "192.168.1.0/24"],
},
// 其他配置...
}
app.use('*', middlewareBundle(config))CORS 默认配置
CORS 中间件的默认配置与 Hono 官方 CORS 中间件保持一致:
cors: {
enabled: true,
origin: "*", // 允许所有来源
allowMethods: [ // 允许的 HTTP 方法
"GET", "HEAD", "PUT",
"POST", "DELETE", "PATCH"
],
allowHeaders: [], // 允许的请求头(空数组,自动处理)
exposeHeaders: [], // 暴露的响应头(空数组)
credentials: undefined, // 是否允许携带凭证(默认不设置)
maxAge: undefined, // 预检请求缓存时间(默认不设置)
}重要提示:
- 生产环境建议设置具体的
origin而不是"*" credentials: true时不能使用origin: "*",必须指定具体域名allowHeaders为空数组时会自动处理Access-Control-Request-Headers请求头
🌐 CORS 跨域配置
生产环境配置
app.use("*", middlewareBundle({
// 日志配置
logging: {
service: "my-api-production",
enablePrettyPrint: false,
},
// 安全头部配置 - 支持跨域
secureHeaders: {
contentSecurityPolicy: "default-src 'self'; connect-src *;",
xFrameOptions: "SAMEORIGIN",
},
// 速率限制
rateLimit: {
limit: 1000,
},
// 超时和请求体大小限制
timeout: {
enabled: true,
timeout: 30000,
},
bodyLimit: {
enabled: true,
},
// 性能监控跨域
timing: {
crossOrigin: true,
},
// 使用默认值:cors: origin: "*" (允许所有跨域)
}));开发环境配置
app.use("*", middlewareBundle({
cors: {
origin: "*",
},
secureHeaders: {
contentSecurityPolicy: "default-src 'self'; connect-src *;",
xFrameOptions: "SAMEORIGIN",
},
}));HTTPS/HTTP 混合内容问题
如果遇到 Access to XMLHttpRequest has been blocked by CORS policy 错误:
// 方案1:使用代理
// vite.config.js
export default {
server: {
proxy: {
'/api': {
target: 'https://your-api.com',
changeOrigin: true,
}
}
}
}Content Security Policy 配置说明
API服务推荐配置:
contentSecurityPolicy: "default-src 'self'; connect-src *;"各部分说明:
default-src 'self'- 默认只允许同源资源connect-src *- 允许所有跨域API调用
其他配置选项:
// 最宽松配置(开发环境,不推荐生产环境)
contentSecurityPolicy: "default-src * 'unsafe-inline' 'unsafe-eval';"
// 最严格配置(生产环境,可能影响功能)
contentSecurityPolicy: "default-src 'self'; connect-src 'self' https://yourdomain.com;"
// 完整跨域配置(包含所有资源类型)
contentSecurityPolicy: "default-src 'self'; connect-src *; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src * data:; font-src * data:;"API服务配置说明:
- 纯API接口 - 只需要
connect-src *允许跨域调用 - 无前端资源 - 不需要
script-src、style-src等配置 - 安全性高 - 最小化配置,减少安全风险
安全考虑:
'unsafe-inline'- 允许内联脚本,存在XSS风险'unsafe-eval'- 允许动态代码执行,存在安全风险*- 允许所有来源,降低安全性
推荐策略:
- API服务 - 使用
default-src 'self'; connect-src *; - 开发环境 - 可以使用最宽松配置
- 生产环境 - 根据实际需求调整,优先考虑安全性
🎯 标准化错误格式
为了提供一致的错误处理体验,我们对某些中间件进行了重新封装,确保它们返回标准化的错误格式。
标准错误响应格式
所有重新封装的中间件都使用统一的错误响应格式:
{
"success": false,
"code": 41301, // 错误代码
"message": "请求体过大", // 中文错误消息
"data": null
}重新封装的中间件
bodyLimit 中间件
原始 Hono 中间件问题:
- 返回简单的 "Payload Too Large" 文本响应
- 错误格式不一致,难以统一处理
我们的改进:
- 返回标准化的 JSON 错误响应
- 使用
CodeEnum.RequestBodyTooLarge(41301) - 支持自定义错误消息
- 保持与 Hono 官方中间件完全兼容
import { bodyLimit } from '@huyooo/hono-middlewares/core'
// 基础使用
app.use('*', bodyLimit({ maxSize: 1024 * 1024 })) // 1MB
// 自定义错误消息
app.use('*', bodyLimit({
maxSize: 1024 * 1024,
message: '文件大小不能超过 1MB'
}))timeout 中间件
原始 Hono 中间件问题:
- 抛出
HTTPException,错误格式不统一 - 难以在全局错误处理器中统一处理
我们的改进:
- 返回标准化的 JSON 错误响应
- 使用
CodeEnum.GatewayTimeout(50401) - 支持自定义错误消息
- 保持向后兼容性
import { timeout } from '@huyooo/hono-middlewares/core'
// 基础使用(向后兼容)
app.use('*', timeout(5000)) // 5秒
// 选项对象配置
app.use('*', timeout({
duration: 5000,
message: '请求处理时间过长,请稍后重试'
}))csrf 中间件
原始 Hono 中间件问题:
- 错误响应格式不统一
- 难以在全局错误处理器中统一处理
我们的改进:
- 返回标准化的 JSON 错误响应
- 使用
CodeEnum.UnauthorizedAccess(40901) - 支持自定义错误消息
- 保持与 Hono 官方中间件完全兼容
import { csrf } from '@huyooo/hono-middlewares/core'
// 基础使用
app.use('*', csrf())
// 自定义 origin 配置
app.use('*', csrf({
origin: 'https://yourdomain.com'
}))
// 自定义错误消息
app.use('*', csrf({
origin: 'https://yourdomain.com',
message: 'CSRF 验证失败,请检查请求来源'
}))ipRestriction 中间件
原始 Hono 中间件问题:
- 错误响应格式不统一
- 难以在全局错误处理器中统一处理
我们的改进:
- 返回标准化的 JSON 错误响应
- 使用
CodeEnum.UnauthorizedAccess(40901) - 支持自定义错误消息
- 保持与 Hono 官方中间件完全兼容
import { ipRestriction } from '@huyooo/hono-middlewares/core'
// 基础使用
app.use('*', ipRestriction({
getConnInfo: getConnInfo
}))
// 配置 IP 限制规则
app.use('*', ipRestriction({
getConnInfo: getConnInfo,
denyList: ['192.168.1.100'],
allowList: ['127.0.0.1', '::1']
}))
// 自定义错误消息
app.use('*', ipRestriction({
getConnInfo: getConnInfo,
denyList: ['192.168.1.100'],
message: 'IP 地址访问被拒绝'
}))错误代码定义
export enum CodeEnum {
// ... 其他错误代码
RequestBodyTooLarge = 41301, // 请求体过大
GatewayTimeout = 50401, // 网关超时
UnauthorizedAccess = 40901, // 未授权访问(CSRF、IP限制等)
TooManyRequests = 42901, // 请求过于频繁(速率限制)
// ... 其他错误代码
}优势
- 一致性: 所有中间件错误都使用相同的响应格式
- 可维护性: 统一的错误处理逻辑,易于维护和扩展
- 用户体验: 前端可以统一处理错误响应
- 向后兼容: 保持与原始 Hono 中间件的 API 兼容性
- 类型安全: 完整的 TypeScript 类型支持
🔑 认证中间件详细说明
apiKeyAuth 中间件
API Key 认证中间件,用于验证 API Key 和 Secret Key 的有效性。
功能特性
- 🔐 双重验证: 验证 API Key ID 和 Secret Key
- 🌐 外部验证: 调用外部 API 进行验证
- 📊 上下文存储: 将验证信息存储在 Hono Context 中
- 🛡️ 错误处理: 标准化的错误响应格式
- 🔄 用户信息: 自动获取并存储用户信息(如果可用)
基本使用
import { apiKeyAuth } from '@huyooo/hono-middlewares'
// 基础使用
app.use('/api/*', apiKeyAuth())
// 在路由中使用
app.get('/api/protected', apiKeyAuth(), (c) => {
const apiKeyInfo = c.get('apiKeyInfo')
const userInfo = c.get('userInfo')
return c.json({ message: 'Protected route', apiKeyInfo, userInfo })
})请求头要求
// 必需在请求头中包含
headers: {
'x-api-key': 'your-api-key-id',
'x-secret-key': 'your-secret-key'
}验证流程
- 检查请求头: 验证
x-api-key和x-secret-key是否存在 - 调用验证 API: 向
https://ones.huyooo.com/restfulApi/verify/apiKey发送验证请求 - 存储验证结果: 将验证信息存储在
c.get('apiKeyInfo')中 - 存储用户信息: 如果验证成功且包含用户信息,存储在
c.get('userInfo')中
Context 变量
// API Key 信息
interface ApiKeyInfo {
apiKeyId: string
verified: boolean
timestamp: string
creatorId: string
data: any
}
// 用户信息(如果可用)
interface UserInfo {
id: string
email: string
nickname: string
// ... 其他用户字段
}
// 在路由中获取
app.get('/api/data', apiKeyAuth(), (c) => {
const apiKeyInfo = c.get('apiKeyInfo') as ApiKeyInfo
const userInfo = c.get('userInfo') as UserInfo | undefined
return c.json({
message: 'Success',
apiKey: apiKeyInfo.apiKeyId,
creator: apiKeyInfo.creatorId,
user: userInfo
})
})错误处理
所有错误响应都使用标准格式,HTTP 状态码为 200:
// 缺少 API Key
{
"success": false,
"code": 40001,
"message": "缺少 API Key ID",
"data": null
}
// 缺少 Secret Key
{
"success": false,
"code": 40001,
"message": "缺少 Secret Key",
"data": null
}
// 验证失败
{
"success": false,
"code": 40101,
"message": "API Key 验证失败",
"data": null
}
// 网络错误
{
"success": false,
"code": 40101,
"message": "API Key 验证请求失败",
"data": null
}使用场景
- API 服务认证: 为第三方应用提供 API 访问
- 微服务间通信: 服务间的身份验证
- 自动化脚本: 脚本和工具的 API 访问
- 移动应用: 移动应用的 API 认证
安全建议
- 🔒 使用 HTTPS 传输 API Key 和 Secret Key
- 🔑 定期轮换 Secret Key
- 📝 记录 API Key 的使用日志
- 🚫 不要在客户端代码中暴露 Secret Key
- ⏰ 设置合理的 API Key 过期时间
auth 中间件
JWT 认证中间件,用于验证用户身份。
功能特性
- 🔐 JWT 验证: 验证 Authorization header 中的 JWT token
- 🆔 应用验证: 验证
app-idheader 的有效性 - 👤 用户信息: 获取并存储用户信息
- 🛡️ 错误处理: 标准化的错误响应格式
基本使用
import { auth } from '@huyooo/hono-middlewares'
// 基础使用
app.use('/protected/*', auth())
// 在路由中使用
app.get('/protected/profile', auth(), (c) => {
const userInfo = c.get('userInfo')
return c.json({ message: 'User profile', userInfo })
})请求头要求
// 必需在请求头中包含
headers: {
'authorization': 'Bearer your-jwt-token',
'app-id': 'your-application-id'
}验证流程
- 检查请求头: 验证
authorization和app-id是否存在 - 调用用户 API: 向
https://ones.huyooo.com/restfulApi/users/profile发送验证请求 - 存储用户信息: 将用户信息存储在
c.get('userInfo')中
Context 变量
// 用户信息
interface UserInfo {
id: string
email: string
nickname: string
// ... 其他用户字段
}
// 在路由中获取
app.get('/protected/data', auth(), (c) => {
const userInfo = c.get('userInfo') as UserInfo
return c.json({
message: 'Success',
userId: userInfo.id,
userEmail: userInfo.email
})
})错误处理
所有错误响应都使用标准格式,HTTP 状态码为 200:
// 缺少 Authorization header
{
"success": false,
"code": 40101,
"message": "未携带authorization header",
"data": null
}
// 缺少 app-id
{
"success": false,
"code": 40002,
"message": "缺少必需的应用ID",
"data": null
}
// 认证失败
{
"success": false,
"code": 40101,
"message": "认证失败",
"data": null
}conditionalAuth 中间件
智能条件认证中间件,能够根据请求头中的 API Key 是否存在来自动选择不同的认证方式。
功能特性
- 🤖 智能选择: 自动检测 API Key 存在性,选择相应认证方式
- 🔄 双重认证: 支持 API Key 认证和 JWT 认证两种方式
- 🎯 灵活配置: 可自定义 API Key 请求头名称
- 🐛 调试支持: 可选的调试日志输出
- 🛡️ 错误处理: 标准化的错误响应格式
认证逻辑
- 检测 API Key: 检查请求头中是否包含
x-api-key(可自定义) - 选择认证方式:
- 如果存在 API Key → 使用
apiKeyAuth()中间件 - 如果不存在 API Key → 使用
auth()中间件
- 如果存在 API Key → 使用
- 执行认证: 调用相应的认证中间件进行验证
基本使用
import { conditionalAuth } from '@huyooo/hono-middlewares'
// 基础使用(使用默认配置)
app.use('/api/*', conditionalAuth())
// 自定义配置
app.use('/api/*', conditionalAuth({
apiKeyHeader: 'x-api-key', // 自定义 API Key 请求头名称
enableDebugLogs: true, // 启用调试日志
message: '自定义认证失败消息' // 自定义错误消息
}))配置选项
interface ConditionalAuthOptions {
apiKeyHeader?: string // API Key 请求头名称,默认 'x-api-key'
enableDebugLogs?: boolean // 是否启用调试日志,默认 false
message?: string // 自定义错误消息
}使用场景
- 混合认证系统: 同时支持 API Key 和 JWT 认证的应用
- 渐进式迁移: 从 API Key 认证迁移到 JWT 认证
- 多客户端支持: 不同客户端使用不同认证方式
- 开发测试: 开发环境使用 API Key,生产环境使用 JWT
请求示例
使用 API Key 认证:
curl -H "x-api-key: your-api-key" \
-H "x-secret-key: your-secret-key" \
https://api.example.com/data使用 JWT 认证:
curl -H "authorization: Bearer your-jwt-token" \
-H "app-id: your-app-id" \
https://api.example.com/data调试日志
启用调试日志后,会输出详细的认证流程信息:
app.use('/api/*', conditionalAuth({ enableDebugLogs: true }))
// 输出示例:
// [conditionalAuth] 中间件开始执行
// [conditionalAuth] 请求路径: /api/data
// [conditionalAuth] 请求方法: GET
// [conditionalAuth] 完整URL: https://api.example.com/api/data
// [conditionalAuth] 检测到 x-api-key: 存在
// [conditionalAuth] 执行 API Key 鉴权路径错误处理
所有错误响应都使用标准格式,HTTP 状态码为 200:
{
"success": false,
"code": 40101,
"message": "条件鉴权失败,请检查认证信息",
"data": null
}最佳实践
- 统一路由: 将需要认证的路由统一使用
conditionalAuth - 调试开发: 开发环境启用调试日志,生产环境关闭
- 错误消息: 根据业务需求自定义错误消息
- 监控日志: 记录认证方式选择,便于分析和优化
🔒 IP 限制配置
IP 限制中间件基于 Hono 官方的 ip-restriction 中间件,支持 IPv4 和 IPv6 地址限制。
基本配置
import { getConnInfo } from '@hono/node-server/conninfo'; // Node.js 环境
app.use("*", middlewareBundle({
ipRestriction: {
enabled: true,
getConnInfo: getConnInfo, // 必须提供,根据运行环境选择
denyList: ["192.168.1.100", "10.0.0.0/8"],
allowList: ["127.0.0.1", "::1", "192.168.1.0/24"],
},
}));支持的 IP 规则格式
IPv4
192.168.2.0- 静态 IP 地址192.168.2.0/24- CIDR 表示法*- 匹配所有地址
IPv6
::1- 静态 IP 地址::1/10- CIDR 表示法*- 匹配所有地址
不同环境的 getConnInfo
// Node.js 环境
import { getConnInfo } from '@hono/node-server/conninfo';
// Bun 环境
import { getConnInfo } from 'hono/bun';
// Deno 环境
import { getConnInfo } from 'hono/deno';
// Cloudflare Workers 环境
import { getConnInfo } from 'hono/cloudflare-workers';配置说明
- enabled: 是否启用 IP 限制
- getConnInfo: 获取连接信息的函数(必须提供,根据运行环境选择)
- denyList: 拒绝列表,拒绝这些 IP 访问
- allowList: 允许列表,只允许这些 IP 访问(如果设置了 allowList,则只有列表中的 IP 可以访问)
使用场景
- 内网访问限制: 只允许特定网段的 IP 访问
- 黑名单: 拒绝特定 IP 或网段访问
- 白名单: 只允许特定 IP 或网段访问
- 安全防护: 防止恶意 IP 攻击
📖 更多示例
查看 examples/ 目录获取更多使用示例:
examples/basic-usage.ts- 基础使用示例examples/commonMiddlewares-usage.ts- 综合中间件使用示例examples/new-middlewares-usage.ts- 新中间件使用示例examples/core-middlewares-usage.ts- 官方中间件单独使用示例examples/package-import-demo.ts- 包导入方式演示examples/cors-defaults-demo.ts- CORS默认值演示examples/ip-restriction-usage.ts- IP 限制使用示例examples/ip-restriction-environments.ts- 不同环境 IP 限制示例examples/apiKeyAuth-usage.ts- API Key 认证使用示例examples/conditionalAuth-usage.ts- 条件认证使用示例
