feat: 添加API授权中间件

为所有API接口添加授权验证,要求请求头中包含有效的API密钥才能访问。

主要变更:
- 新增授权中间件 (internal/middleware/auth.go)
  - 验证 X-API-Key 请求头
  - 密钥值为 xn001624.
  - 无效密钥返回 401 Unauthorized

- 更新路由配置 (cmd/server/main.go)
  - 使用路由组统一应用授权中间件
  - 保护所有文件和存储桶操作接口
  - Swagger 和 Web UI 保持公开访问

- 新增授权使用文档 (docs/AUTH_GUIDE.md)
  - 多语言使用示例 (cURL, JavaScript, Python)
  - 完整的错误说明和授权范围

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root 2026-01-05 20:22:04 +08:00
parent 5b66e7d3e7
commit 11fc10ba8a
3 changed files with 179 additions and 16 deletions

View File

@ -9,6 +9,7 @@ import (
"file-system/internal/domain/repository"
"file-system/internal/infrastructure/mediator"
"file-system/internal/infrastructure/s3"
"file-system/internal/middleware"
"io"
"net/http"
@ -84,25 +85,29 @@ func main() {
c.Next()
})
// Routes
// File operations
r.POST("/files/upload", fileEndpoint.UploadFile)
r.GET("/files/download", fileEndpoint.DownloadFile)
r.GET("/files/list", fileEndpoint.ListFiles)
r.GET("/files/preview", fileEndpoint.GetPreviewURL)
// API授权中间件组
api := r.Group("/")
api.Use(middleware.AuthMiddleware())
{
// File operations
api.POST("/files/upload", fileEndpoint.UploadFile)
api.GET("/files/download", fileEndpoint.DownloadFile)
api.GET("/files/list", fileEndpoint.ListFiles)
api.GET("/files/preview", fileEndpoint.GetPreviewURL)
// Delete file
r.DELETE("/files/delete", fileEndpoint.DeleteFile)
// Delete file
api.DELETE("/files/delete", fileEndpoint.DeleteFile)
// Multipart Upload
r.POST("/files/multipart/init", fileEndpoint.InitMultipart)
r.PUT("/files/multipart/part", fileEndpoint.UploadPart)
r.POST("/files/multipart/complete", fileEndpoint.CompleteMultipart)
// Multipart Upload
api.POST("/files/multipart/init", fileEndpoint.InitMultipart)
api.PUT("/files/multipart/part", fileEndpoint.UploadPart)
api.POST("/files/multipart/complete", fileEndpoint.CompleteMultipart)
// Bucket operations
r.POST("/buckets", bucketEndpoint.CreateBucket)
r.GET("/buckets", bucketEndpoint.ListBuckets)
r.DELETE("/buckets", bucketEndpoint.DeleteBucket)
// Bucket operations
api.POST("/buckets", bucketEndpoint.CreateBucket)
api.GET("/buckets", bucketEndpoint.ListBuckets)
api.DELETE("/buckets", bucketEndpoint.DeleteBucket)
}
// Swagger
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

124
docs/AUTH_GUIDE.md Normal file
View File

@ -0,0 +1,124 @@
# API 授权使用指南
## 概述
所有 API 接口现在都需要通过授权验证才能访问。每个请求都必须在请求头中包含有效的 API 密钥。
## API 密钥
- **密钥值**: `xn001624`
- **请求头名称**: `X-API-Key`
## 使用方法
### 示例 1: 使用 cURL
```bash
# 上传文件
curl -X POST http://localhost:8080/files/upload \
-H "X-API-Key: xn001624" \
-F "file=@/path/to/your/file.txt" \
-F "bucket=my-bucket" \
-F "path=/uploads/"
# 列出存储桶
curl -X GET http://localhost:8080/buckets \
-H "X-API-Key: xn001624"
# 下载文件
curl -X GET "http://localhost:8080/files/download?bucket=my-bucket&path=/uploads/file.txt" \
-H "X-API-Key: xn001624" \
-o downloaded_file.txt
```
### 示例 2: 使用 JavaScript (Fetch)
```javascript
const response = await fetch('http://localhost:8080/buckets', {
method: 'GET',
headers: {
'X-API-Key': 'xn001624',
'Content-Type': 'application/json'
}
});
const data = await response.json();
console.log(data);
```
### 示例 3: 使用 Python (requests)
```python
import requests
headers = {
'X-API-Key': 'xn001624'
}
# 列出存储桶
response = requests.get(
'http://localhost:8080/buckets',
headers=headers
)
print(response.json())
```
### 示例 4: 使用 Postman
1. 打开 Postman
2. 在 Headers 选项卡中添加新的 key-value 对:
- Key: `X-API-Key`
- Value: `xn001624`
3. 发送请求
## 错误响应
如果未提供 API 密钥或密钥无效,将返回以下错误:
**状态码**: `401 Unauthorized`
**响应体**:
```json
{
"code": 401,
"message": "未授权请在请求头中提供有效的API密钥",
"error": "Missing or invalid API key"
}
```
## 授权范围
以下所有 API 接口都需要授权:
### 文件操作
- `POST /files/upload` - 上传文件
- `GET /files/download` - 下载文件
- `GET /files/list` - 列出文件
- `GET /files/preview` - 获取文件预览URL
- `DELETE /files/delete` - 删除文件
### 分片上传
- `POST /files/multipart/init` - 初始化分片上传
- `PUT /files/multipart/part` - 上传分片
- `POST /files/multipart/complete` - 完成分片上传
### 存储桶操作
- `POST /buckets` - 创建存储桶
- `GET /buckets` - 列出存储桶
- `DELETE /buckets` - 删除存储桶
### 无需授权的接口
以下接口不需要授权:
- `GET /swagger/*` - Swagger 文档
- `GET /web/*` - Web UI
- `GET /` - 根路径重定向
## 安全建议
1. **不要在客户端代码中硬编码 API 密钥**
2. **使用环境变量存储 API 密钥**
3. **定期更换 API 密钥**
4. **在生产环境中使用 HTTPS**
5. **实施速率限制以防止滥用**
## 配置
如需修改 API 密钥,请编辑文件:
`internal/middleware/auth.go`
修改 `API_KEY_VALUE` 常量的值即可。

View File

@ -0,0 +1,34 @@
package middleware
import (
"net/http"
"github.com/gin-gonic/gin"
)
const (
API_KEY_HEADER = "X-API-Key"
API_KEY_VALUE = "xn001624."
)
// AuthMiddleware 验证API密钥的中间件
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 从请求头中获取API密钥
apiKey := c.GetHeader(API_KEY_HEADER)
// 验证密钥是否正确
if apiKey != API_KEY_VALUE {
c.JSON(http.StatusUnauthorized, gin.H{
"code": http.StatusUnauthorized,
"message": "未授权请在请求头中提供有效的API密钥",
"error": "Missing or invalid API key",
})
c.Abort()
return
}
// 密钥验证通过,继续处理请求
c.Next()
}
}