diff --git a/cmd/server/main.go b/cmd/server/main.go index e22dce3..3447bfc 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -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)) diff --git a/docs/AUTH_GUIDE.md b/docs/AUTH_GUIDE.md new file mode 100644 index 0000000..d646ae7 --- /dev/null +++ b/docs/AUTH_GUIDE.md @@ -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` 常量的值即可。 diff --git a/internal/middleware/auth.go b/internal/middleware/auth.go new file mode 100644 index 0000000..1b5d078 --- /dev/null +++ b/internal/middleware/auth.go @@ -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() + } +}