# CarrotSkin 后端 API 文档 ## 概述 本文档总结了 CarrotSkin 后端 API,主要关注前端需要的接口,不包括 Yggdrasil 相关接口(除了更换 Yggdrasil 密码)。 ## 基础信息 - **基础URL**: `/api/v1` - **认证方式**: JWT Bearer Token - **数据格式**: JSON - **字符编码**: UTF-8 ## 通用响应格式 所有API响应都遵循以下格式: ```json { "code": 200, "message": "操作成功", "data": { // 具体数据内容 } } ``` 分页响应格式: ```json { "code": 200, "message": "操作成功", "data": { "list": [], "total": 100, "page": 1, "page_size": 20, "total_pages": 5 } } ``` ## 认证相关 API ### 1. 用户注册 - **URL**: `POST /api/v1/auth/register` - **认证**: 无需认证 - **请求参数**: ```json { "username": "newuser", // 用户名,3-50字符 "email": "user@example.com", // 邮箱地址 "password": "password123", // 密码,6-128字符 "verification_code": "123456", // 邮箱验证码,6位数字 "avatar": "https://example.com/avatar.png" // 可选,头像URL } ``` - **响应数据**: ```json { "code": 200, "message": "注册成功", "data": { "token": "jwt_token_here", "user_info": { "id": 1, "username": "newuser", "email": "user@example.com", "avatar": "https://example.com/avatar.png", "points": 0, "role": "user", "status": 1, "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } } } ``` ### 2. 用户登录 - **URL**: `POST /api/v1/auth/login` - **认证**: 无需认证 - **请求参数**: ```json { "username": "testuser", // 用户名或邮箱 "password": "password123" // 密码 } ``` - **响应数据**: ```json { "code": 200, "message": "登录成功", "data": { "token": "jwt_token_here", "user_info": { "id": 1, "username": "testuser", "email": "test@example.com", "avatar": "https://example.com/avatar.png", "points": 100, "role": "user", "status": 1, "last_login_at": "2025-10-01T12:00:00Z", "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } } } ``` ### 3. 发送验证码 - **URL**: `POST /api/v1/auth/send-code` - **认证**: 无需认证 - **请求参数**: ```json { "email": "user@example.com", // 邮箱地址 "type": "register" // 类型: register/reset_password/change_email } ``` - **响应数据**: ```json { "code": 200, "message": "验证码已发送,请查收邮件", "data": { "message": "验证码已发送,请查收邮件" } } ``` ### 4. 重置密码 - **URL**: `POST /api/v1/auth/reset-password` - **认证**: 无需认证 - **请求参数**: ```json { "email": "user@example.com", // 邮箱地址 "verification_code": "123456", // 邮箱验证码 "new_password": "newpassword123" // 新密码 } ``` - **响应数据**: ```json { "code": 200, "message": "密码重置成功", "data": { "message": "密码重置成功" } } ``` ## 用户相关 API ### 1. 获取用户信息 - **URL**: `GET /api/v1/user/profile` - **认证**: 需要JWT认证 - **请求参数**: 无 - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "id": 1, "username": "testuser", "email": "test@example.com", "avatar": "https://example.com/avatar.png", "points": 100, "role": "user", "status": 1, "last_login_at": "2025-10-01T12:00:00Z", "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } } ``` ### 2. 更新用户信息 - **URL**: `PUT /api/v1/user/profile` - **认证**: 需要JWT认证 - **请求参数**: ```json { "avatar": "https://example.com/new-avatar.png", // 可选,新头像URL "old_password": "oldpassword123", // 可选,修改密码时需要 "new_password": "newpassword123" // 可选,新密码 } ``` - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "id": 1, "username": "testuser", "email": "test@example.com", "avatar": "https://example.com/new-avatar.png", "points": 100, "role": "user", "status": 1, "last_login_at": "2025-10-01T12:00:00Z", "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } } ``` ### 3. 生成头像上传URL - **URL**: `POST /api/v1/user/avatar/upload-url` - **认证**: 需要JWT认证 - **请求参数**: ```json { "file_name": "avatar.png" // 文件名 } ``` - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "post_url": "https://rustfs.example.com/avatars", "form_data": { "key": "user_1/xxx.png", "policy": "base64_policy", "x-amz-signature": "signature" }, "avatar_url": "https://rustfs.example.com/avatars/user_1/xxx.png", "expires_in": 900 } } ``` ### 4. 更新头像URL - **URL**: `PUT /api/v1/user/avatar` - **认证**: 需要JWT认证 - **请求参数**: - Query参数: `avatar_url` - 头像URL - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "id": 1, "username": "testuser", "email": "test@example.com", "avatar": "https://example.com/new-avatar.png", "points": 100, "role": "user", "status": 1, "last_login_at": "2025-10-01T12:00:00Z", "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } } ``` ### 5. 更换邮箱 - **URL**: `POST /api/v1/user/change-email` - **认证**: 需要JWT认证 - **请求参数**: ```json { "new_email": "newemail@example.com", // 新邮箱地址 "verification_code": "123456" // 邮箱验证码 } ``` - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "id": 1, "username": "testuser", "email": "newemail@example.com", "avatar": "https://example.com/avatar.png", "points": 100, "role": "user", "status": 1, "last_login_at": "2025-10-01T12:00:00Z", "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } } ``` ### 6. 重置Yggdrasil密码 - **URL**: `POST /api/v1/user/yggdrasil-password/reset` - **认证**: 需要JWT认证 - **请求参数**: 无 - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "password": "new_yggdrasil_password" } } ``` ## 材质相关 API ### 1. 搜索材质 - **URL**: `GET /api/v1/texture` - **认证**: 无需认证 - **请求参数**: - Query参数: - `keyword`: 搜索关键词 - `type`: 材质类型 (SKIN/CAPE) - `public_only`: 是否只搜索公开材质 (true/false) - `page`: 页码,默认1 - `page_size`: 每页数量,默认20 - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "list": [ { "id": 1, "uploader_id": 1, "name": "My Skin", "description": "A cool skin", "type": "SKIN", "url": "https://rustfs.example.com/textures/xxx.png", "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "size": 2048, "is_public": true, "download_count": 100, "favorite_count": 50, "is_slim": false, "status": 1, "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } ], "total": 100, "page": 1, "page_size": 20, "total_pages": 5 } } ``` ### 2. 获取材质详情 - **URL**: `GET /api/v1/texture/{id}` - **认证**: 无需认证 - **请求参数**: - 路径参数: `id` - 材质ID - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "id": 1, "uploader_id": 1, "name": "My Skin", "description": "A cool skin", "type": "SKIN", "url": "https://rustfs.example.com/textures/xxx.png", "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "size": 2048, "is_public": true, "download_count": 100, "favorite_count": 50, "is_slim": false, "status": 1, "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } } ``` ### 3. 直接上传材质文件(推荐) - **URL**: `POST /api/v1/texture/upload` - **认证**: 需要JWT认证 - **Content-Type**: `multipart/form-data` - **请求参数**: - `file`: 材质文件(PNG格式,1KB-10MB) - `name`: 材质名称(必填,1-100字符) - `description`: 材质描述(可选,最多500字符) - `type`: 材质类型(可选,默认SKIN,可选值:SKIN/CAPE) - `is_public`: 是否公开(可选,默认false,true/false) - `is_slim`: 是否为细臂模型(可选,默认false,true/false) - **说明**: - 后端会自动计算文件的SHA256哈希值 - 如果已存在相同哈希的材质,会复用已存在的文件URL,不重复上传 - 允许多次上传相同哈希的材质(包括同一用户),每次都会创建新的数据库记录 - 文件存储路径格式:`{type}/{hash[:2]}/{hash[2:4]}/{hash}.png` - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "id": 1, "uploader_id": 1, "name": "My Cool Skin", "description": "A very cool skin", "type": "SKIN", "url": "https://rustfs.example.com/textures/skin/e3/b0/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.png", "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "size": 2048, "is_public": true, "download_count": 0, "favorite_count": 0, "is_slim": false, "status": 1, "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } } ``` ### 4. 生成材质上传URL(兼容接口) - **URL**: `POST /api/v1/texture/upload-url` - **认证**: 需要JWT认证 - **请求参数**: ```json { "file_name": "skin.png", // 文件名 "texture_type": "SKIN" // 材质类型: SKIN/CAPE } ``` - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "post_url": "https://rustfs.example.com/textures", "form_data": { "key": "user_1/skin/xxx.png", "policy": "base64_policy", "x-amz-signature": "signature" }, "texture_url": "https://rustfs.example.com/textures/user_1/skin/xxx.png", "expires_in": 900 } } ``` ### 5. 创建材质记录(配合预签名URL使用) - **URL**: `POST /api/v1/texture` - **认证**: 需要JWT认证 - **请求参数**: ```json { "name": "My Cool Skin", // 材质名称,1-100字符 "description": "A very cool skin", // 描述,最多500字符 "type": "SKIN", // 材质类型: SKIN/CAPE "url": "https://rustfs.example.com/textures/user_1/skin/xxx.png", // 材质URL "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", // SHA256哈希 "size": 2048, // 文件大小(字节) "is_public": true, // 是否公开 "is_slim": false // 是否为细臂模型(Alex) } ``` - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "id": 1, "uploader_id": 1, "name": "My Cool Skin", "description": "A very cool skin", "type": "SKIN", "url": "https://rustfs.example.com/textures/user_1/skin/xxx.png", "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "size": 2048, "is_public": true, "download_count": 0, "favorite_count": 0, "is_slim": false, "status": 1, "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } } ``` ### 6. 更新材质 - **URL**: `PUT /api/v1/texture/{id}` - **认证**: 需要JWT认证 - **请求参数**: - 路径参数: `id` - 材质ID - 请求体: ```json { "name": "Updated Skin Name", // 可选,新名称 "description": "Updated description", // 可选,新描述 "is_public": false // 可选,是否公开 } ``` - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "id": 1, "uploader_id": 1, "name": "Updated Skin Name", "description": "Updated description", "type": "SKIN", "url": "https://rustfs.example.com/textures/user_1/skin/xxx.png", "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "size": 2048, "is_public": false, "download_count": 100, "favorite_count": 50, "is_slim": false, "status": 1, "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } } ``` ### 7. 删除材质 - **URL**: `DELETE /api/v1/texture/{id}` - **认证**: 需要JWT认证 - **请求参数**: - 路径参数: `id` - 材质ID - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": null } ``` ### 8. 切换收藏状态 - **URL**: `POST /api/v1/texture/{id}/favorite` - **认证**: 需要JWT认证 - **请求参数**: - 路径参数: `id` - 材质ID - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "is_favorited": true } } ``` ### 9. 获取用户上传的材质列表 - **URL**: `GET /api/v1/texture/my` - **认证**: 需要JWT认证 - **请求参数**: - Query参数: - `page`: 页码,默认1 - `page_size`: 每页数量,默认20 - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "list": [ { "id": 1, "uploader_id": 1, "name": "My Skin", "description": "A cool skin", "type": "SKIN", "url": "https://rustfs.example.com/textures/xxx.png", "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "size": 2048, "is_public": true, "download_count": 100, "favorite_count": 50, "is_slim": false, "status": 1, "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } ], "total": 50, "page": 1, "page_size": 20, "total_pages": 3 } } ``` ### 10. 获取用户收藏的材质列表 - **URL**: `GET /api/v1/texture/favorites` - **认证**: 需要JWT认证 - **请求参数**: - Query参数: - `page`: 页码,默认1 - `page_size`: 每页数量,默认20 - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "list": [ { "id": 1, "uploader_id": 2, "name": "Cool Skin", "description": "A very cool skin", "type": "SKIN", "url": "https://rustfs.example.com/textures/xxx.png", "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "size": 2048, "is_public": true, "download_count": 100, "favorite_count": 50, "is_slim": false, "status": 1, "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } ], "total": 30, "page": 1, "page_size": 20, "total_pages": 2 } } ``` ## 档案相关 API ### 1. 创建档案 - **URL**: `POST /api/v1/profile` - **认证**: 需要JWT认证 - **请求参数**: ```json { "name": "PlayerName" // 角色名,1-16字符 } ``` - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "uuid": "550e8400-e29b-41d4-a716-446655440000", "user_id": 1, "name": "PlayerName", "skin_id": null, "cape_id": null, "is_active": false, "last_used_at": null, "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } } ``` ### 2. 获取档案列表 - **URL**: `GET /api/v1/profile` - **认证**: 需要JWT认证 - **请求参数**: 无 - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": [ { "uuid": "550e8400-e29b-41d4-a716-446655440000", "user_id": 1, "name": "PlayerName", "skin_id": 1, "cape_id": 2, "is_active": true, "last_used_at": "2025-10-01T12:00:00Z", "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } ] } ``` ### 3. 获取档案详情 - **URL**: `GET /api/v1/profile/{uuid}` - **认证**: 无需认证 - **请求参数**: - 路径参数: `uuid` - 档案UUID - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "uuid": "550e8400-e29b-41d4-a716-446655440000", "user_id": 1, "name": "PlayerName", "skin_id": 1, "cape_id": 2, "is_active": true, "last_used_at": "2025-10-01T12:00:00Z", "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } } ``` ### 4. 更新档案 - **URL**: `PUT /api/v1/profile/{uuid}` - **认证**: 需要JWT认证 - **请求参数**: - 路径参数: `uuid` - 档案UUID - 请求体: ```json { "name": "NewPlayerName", // 可选,新角色名 "skin_id": 1, // 可选,皮肤ID "cape_id": 2 // 可选,披风ID } ``` - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "uuid": "550e8400-e29b-41d4-a716-446655440000", "user_id": 1, "name": "NewPlayerName", "skin_id": 1, "cape_id": 2, "is_active": true, "last_used_at": "2025-10-01T12:00:00Z", "created_at": "2025-10-01T10:00:00Z", "updated_at": "2025-10-01T10:00:00Z" } } ``` ### 5. 删除档案 - **URL**: `DELETE /api/v1/profile/{uuid}` - **认证**: 需要JWT认证 - **请求参数**: - 路径参数: `uuid` - 档案UUID - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "message": "删除成功" } } ``` ### 6. 设置活跃档案 - **URL**: `POST /api/v1/profile/{uuid}/activate` - **认证**: 需要JWT认证 - **请求参数**: - 路径参数: `uuid` - 档案UUID - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "message": "设置成功" } } ``` ## 验证码相关 API ### 1. 生成验证码 - **URL**: `GET /api/v1/captcha/generate` - **认证**: 无需认证 - **请求参数**: 无 - **响应数据**: ```json { "code": 200, "data": { "masterImage": "base64_encoded_master_image", "tileImage": "base64_encoded_tile_image", "captchaId": "captcha_id_here", "y": 100 } } ``` ### 2. 验证验证码 - **URL**: `POST /api/v1/captcha/verify` - **认证**: 无需认证 - **请求参数**: ```json { "captchaId": "captcha_id_here", "dx": 150 // 滑动距离 } ``` - **响应数据**: ```json { "code": 200, "msg": "验证成功" } ``` ## 系统相关 API ### 1. 获取系统配置 - **URL**: `GET /api/v1/system/config` - **认证**: 无需认证 - **请求参数**: 无 - **响应数据**: ```json { "code": 200, "message": "操作成功", "data": { "site_name": "CarrotSkin", "site_description": "A Minecraft Skin Station", "registration_enabled": true, "max_textures_per_user": 100, "max_profiles_per_user": 5 } } ``` ## CustomSkin API ### 1. 获取玩家信息 - **URL**: `GET /api/v1/csl/{username}` - **认证**: 无需认证 - **请求参数**: - 路径参数: `username` - 玩家用户名 - **响应数据**: ```json { "username": "PlayerName", "textures": { "default": "skin_hash_here", "slim": "skin_hash_here", "cape": "cape_hash_here", "elytra": "cape_hash_here" } } ``` 或简化格式: ```json { "username": "PlayerName", "skin": "skin_hash_here" } ``` ### 2. 获取资源文件 - **URL**: `GET /api/v1/csl/textures/{hash}` - **认证**: 无需认证 - **请求参数**: - 路径参数: `hash` - 资源哈希值 - **响应数据**: 二进制文件内容 ## 健康检查 ### 1. 健康检查 - **URL**: `GET /health` - **认证**: 无需认证 - **请求参数**: 无 - **响应数据**: ```json { "status": "ok" } ``` ## 错误码说明 | 错误码 | 说明 | |--------|------| | 200 | 操作成功 | | 400 | 请求参数错误 | | 401 | 未认证或认证失败 | | 403 | 无权限操作 | | 404 | 资源不存在 | | 500 | 服务器内部错误 | ## 认证说明 需要JWT认证的API需要在请求头中添加: ``` Authorization: Bearer {jwt_token} ``` JWT Token在用户登录或注册成功后返回,有效期内可用于访问需要认证的API。