Files
carrotskin/API文档.md
Wu XiangYu 268344c357
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 15m39s
fix: 修复前端多项问题并完善认证流程
- 修复 AuthContext 硬编码 localhost:8080,改用 api.ts 统一的 API_BASE_URL(走环境变量/代理,生产可部署)
- 修复注册页发送验证码绕过 api.ts 直接 raw fetch 的问题,改用统一的 sendVerificationCode
- 修复 SliderCaptcha 验证成功后 captchaId 未透传导致注册人机验证失效的断链
- 修复头像上传契约:预签名URL方式(/user/avatar/upload-url)改为直传(/user/avatar/upload)
- 移除后端不支持的'设置活跃角色'功能(/profile/:uuid/activate)及相关死代码
- 修复分页字段不一致:新增 normalizePaginatedData 兼容后端 per_page 响应
- 强化邮箱正则校验(RFC 标准,禁止连续点/首尾点,TLD>=2字母)
- 移除首页指向无效 /api 页面的'查看API文档'按钮
- 新增 /register /login /signup 重定向路由,统一指向 /auth?mode=
- 同步 API文档.md
2026-07-08 17:36:09 +08:00

9.2 KiB
Raw Blame History

CarrotSkin API 文档基于后端代码2026-07 修订)

本文档由后端 internal/handler/*.go + internal/types/common.go 直接整理而来, 是前后端契约的唯一事实来源。所有路径以 /api/v1 为前缀Yggdrasil / CSL 除外)。

通用约定

统一响应格式

成功:

{ "code": 200, "message": "操作成功", "data": <任意> }

错误:

{ "code": <非200>, "message": "<错误描述>", "error": "<仅非生产环境返回>" }

常用状态码:200 成功 / 201 创建成功 / 400 参数错误 / 401 未授权 / 403 禁止 / 404 不存在 / 500 服务器错误

认证

  • 除"无需认证"标注的接口外,所有 /user/*/profile 写操作、/texture 写操作均需在请求头携带: Authorization: Bearer <jwt_token>
  • JWT 通过登录或注册接口获取。

分页

  • 请求参数:page(页码,默认 1page_size(每页数量,默认 20
  • 响应数据形态(注意:后端返回的字段名是 per_page,且 不含 total_pages
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "list": [ ... ],
    "total": 100,
    "page": 1,
    "per_page": 20
  }
}

一、认证 /auth(无需 JWT

1. 用户注册

  • POST /api/v1/auth/register
  • Body
{
  "username": "newuser",
  "email": "user@example.com",
  "password": "password123",
  "verification_code": "123456",
  "captcha_id": "uuid-xxxx",
  "avatar": "https://example.com/a.png"
}
  • username 350 字符;password 6128verification_code 必填 6 位;
  • captcha_id 必填(来自 POST /captcha/verify 后透传的 captchaId
  • avatar 可选,必须是合法 URL。
  • 响应 data
{
  "token": "<jwt>",
  "user_info": {
    "id": 1, "username": "newuser", "email": "user@example.com",
    "avatar": "", "points": 0, "role": "user", "status": 1,
    "last_login_at": null,
    "created_at": "2026-07-08T10:00:00Z",
    "updated_at": "2026-07-08T10:00:00Z"
  }
}

2. 用户登录

  • POST /api/v1/auth/login
  • Body
{ "username": "newuser 或 user@example.com", "password": "password123" }
  • 响应 data:同注册({ token, user_info })。

3. 发送邮箱验证码

  • POST /api/v1/auth/send-code
  • Body
{ "email": "user@example.com", "type": "register | reset_password | change_email" }
  • 响应 data{ "message": "验证码已发送,请查收邮件" }

4. 重置密码

  • POST /api/v1/auth/reset-password
  • Body
{
  "email": "user@example.com",
  "verification_code": "123456",
  "new_password": "newpassword123"
}
  • 响应 data{ "message": "密码重置成功" }

二、用户 /user(需 JWT

5. 获取当前用户信息

  • GET /api/v1/user/profile
  • 响应 dataUserInfo(同注册返回的 user_info)。

6. 更新用户信息(密码 / 头像 URL

  • PUT /api/v1/user/profile
  • Body
{
  "avatar": "https://example.com/a.png",          // 可选,更新头像 URL
  "old_password": "oldpassword123",                // 修改密码时必填
  "new_password": "newpassword123"                 // 6128
}
  • 响应 data:更新后的 UserInfo

7. 上传头像文件

  • POST /api/v1/user/avatar/uploadmultipart/form-data
  • 字段:file图片文件≤10MB
  • 响应 data
{ "avatar_url": "https://.../avatar.png", "user": { ...UserInfo } }

8. 更新头像 URL外部 URL

  • PUT /api/v1/user/avatar?avatar_url=<url>
  • 响应 dataUserInfo

9. 更换邮箱

  • POST /api/v1/user/change-email
  • Body
{ "new_email": "new@example.com", "verification_code": "123456" }
  • 响应 data:更换后的 UserInfo(新邮箱已生效)。

10. 重置 Yggdrasil 密码

  • POST /api/v1/user/yggdrasil-password/reset
  • 响应 data{ "password": "<新的Yggdrasil密码>" }

11. 获取用户公开信息

  • GET /api/v1/users/public?username=<name>?id=<id>(无需 JWT
  • 响应 data
{
  "id": 1, "username": "testuser", "avatar": "",
  "points": 100, "role": "user", "status": 1,
  "created_at": "2026-07-01T10:00:00Z"
}

三、材质 /texture

12. 搜索材质(公开,无需 JWT

  • GET /api/v1/texture
  • Querykeyword / type=SKIN|CAPE / public_only=true / page / page_size
  • 响应 data:分页结构 { list: TextureInfo[], total, page, per_page }

13. 获取材质详情(公开)

  • GET /api/v1/texture/:id
  • 响应 dataTextureInfo

14. 上传材质(需 JWTmultipart

  • POST /api/v1/texture/upload
  • formDatafile(PNG, ≤32MB)、name(必填)、descriptiontype=SKIN|CAPEis_publicis_slim
  • 响应 dataTextureInfo

15. 更新材质(需 JWT

  • PUT /api/v1/texture/:id
  • Body
{ "name": "新名称", "description": "新描述", "is_public": true }
  • is_public 后端为 *bool,传 true/false 会更新;不传保持不变。
  • 响应 dataTextureInfo

16. 删除材质(需 JWT

  • DELETE /api/v1/texture/:id
  • 响应 datanull

17. 切换收藏(需 JWT

  • POST /api/v1/texture/:id/favorite
  • 响应 data{ "is_favorited": true }

18. 我的上传(需 JWT

  • GET /api/v1/texture/my?page=1&page_size=20
  • 响应 data:分页结构。

19. 我的收藏(需 JWT

  • GET /api/v1/texture/favorites?page=1&page_size=20
  • 响应 data:分页结构。

TextureInfo 字段

id, uploader_id, uploader_username, name, description(omitempty), type(SKIN|CAPE), url, hash, size, is_public, download_count, favorite_count, is_slim, status, created_at, updated_at


四、档案 /profile

⚠️ 后端当前 PUT /profile/:uuid 不支持解除皮肤/披风绑定 UpdateProfileRequest.SkinID / CapeID*int64,仅当非 nil 时才更新; 传 null 与字段缺失都会被 Go 反序列化为 nil,二者无法区分,均被忽略。 因此前端要"移除角色皮肤",需要后端先支持(详见下方《待补齐》)。

20. 获取档案列表(需 JWT

  • GET /api/v1/profileGET /api/v1/profile/
  • 响应 dataProfileInfo[]

21. 创建档案(需 JWT

  • POST /api/v1/profilePOST /api/v1/profile/
  • Body{ "name": "PlayerName" }116 字符)
  • 响应 dataProfileInfo

22. 获取档案详情(公开)

  • GET /api/v1/profile/:uuid
  • 响应 dataProfileInfo

23. 更新档案(需 JWT

  • PUT /api/v1/profile/:uuid
  • Body
{ "name": "NewName", "skin_id": 1, "cape_id": 2 }
  • 当前实现:skin_id/cape_id 传数字会设置;传 null / 缺失均被忽略(无法清空)。
  • 响应 dataProfileInfo

24. 删除档案(需 JWT

  • DELETE /api/v1/profile/:uuid
  • 响应 data{ "message": "删除成功" }

ProfileInfo 字段

uuid, user_id, name, skin_id(omitempty,可空), cape_id(omitempty,可空), last_used_at(omitempty), created_at, updated_at


五、滑动验证码 /captcha(无需 JWT

25. 生成滑动验证码

  • GET /api/v1/captcha/generate
  • 响应(注意:此接口的响应是直接对象,未包裹 data
{
  "code": 200,
  "data": {
    "masterImage": "<base64 主图>",
    "tileImage":   "<base64 滑块图>",
    "captchaId":   "<进程ID注册时需要>",
    "y":           <缺口纵坐标>
  }
}

26. 校验滑动验证码

  • POST /api/v1/captcha/verify
  • Body{ "captchaId": "<id>", "dx": <横坐标> }
  • 响应:{ "code": 200, "msg": "验证成功" }{ "code": 400, "msg": "验证失败,请重试" }

六、Yggdrasil API /api/yggdrasil(独立前缀,供 MC 客户端使用)

  • GET /api/yggdrasil —— 元数据
  • POST /api/yggdrasil/minecraftservices/player/certificates
  • POST /api/yggdrasil/authserver/authenticate
  • POST /api/yggdrasil/authserver/validate
  • POST /api/yggdrasil/authserver/refresh
  • POST /api/yggdrasil/authserver/invalidate
  • POST /api/yggdrasil/authserver/signout
  • GET /api/yggdrasil/sessionserver/session/minecraft/profile/:uuid
  • POST /api/yggdrasil/sessionserver/session/minecraft/join
  • GET /api/yggdrasil/sessionserver/session/minecraft/hasJoined
  • POST /api/yggdrasil/api/profiles/minecraft

七、CustomSkinAPI /api/v1/csl(公开)

  • GET /api/v1/csl/:username —— 获取玩家信息 JSON
  • GET /api/v1/csl/textures/:hash —— 获取资源文件

八、管理员 /api/v1/admin(需 JWT + 管理员)

  • GET /admin/usersGET /admin/users/:id
  • PUT /admin/users/rolePUT /admin/users/status
  • GET /admin/texturesDELETE /admin/textures/:id
  • GET /admin/permissions

待补齐(后端缺陷,影响前端可用性)

  1. PUT /profile/:uuid 不支持清空 skin/cape 现状:SkinID/CapeID *int64 无法区分"未传"与"显式 null"。 建议:改用 json.RawMessage 区分三种语义(缺失=不修改 / null=清空 / 数字=设置), 或新增 remove_skin / remove_cape 布尔字段。前端"移除角色皮肤"依赖此能力。