576 lines
19 KiB
JSON
576 lines
19 KiB
JSON
{
|
||
"openapi": "3.0.3",
|
||
"info": {
|
||
"title": "WebGame 后端接口文档",
|
||
"version": "1.0.0",
|
||
"description": "WebGame 游戏后端 REST API 接口文档。认证采用双 Token 机制:Access Token(30 分钟有效,每次请求携带) + Refresh Token(30 天有效,仅用于刷新 Access Token)。"
|
||
},
|
||
"servers": [
|
||
{
|
||
"url": "http://localhost:8080",
|
||
"description": "本地开发环境"
|
||
}
|
||
],
|
||
"tags": [
|
||
{ "name": "账号", "description": "账号相关接口(登录、注册、刷新令牌,无需认证)" },
|
||
{ "name": "用户", "description": "用户相关接口(需 Access Token 认证)" }
|
||
],
|
||
"paths": {
|
||
"/account/login": {
|
||
"post": {
|
||
"tags": ["账号"],
|
||
"summary": "用户登录",
|
||
"description": "使用用户名和密码进行登录认证,成功返回 Access Token 和 Refresh Token。该接口无需登录即可调用。",
|
||
"operationId": "login",
|
||
"security": [],
|
||
"requestBody": {
|
||
"required": true,
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/LoginRequest" },
|
||
"example": {
|
||
"username": "testuser",
|
||
"password": "123456"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "登录成功,返回双 Token",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"allOf": [
|
||
{ "$ref": "#/components/schemas/ApiResponse" },
|
||
{
|
||
"type": "object",
|
||
"properties": {
|
||
"data": { "$ref": "#/components/schemas/LoginResponse" }
|
||
}
|
||
}
|
||
]
|
||
},
|
||
"example": {
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": {
|
||
"accessToken": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||
"refreshToken": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"400": { "$ref": "#/components/responses/BadRequest" },
|
||
"500": { "$ref": "#/components/responses/InternalError" }
|
||
}
|
||
}
|
||
},
|
||
"/account/register": {
|
||
"post": {
|
||
"tags": ["账号"],
|
||
"summary": "用户注册",
|
||
"description": "注册新账号。用户名长度 3-32 位,密码长度 6-64 位。注册成功后自动登录并返回双 Token。该接口无需登录即可调用。",
|
||
"operationId": "register",
|
||
"security": [],
|
||
"requestBody": {
|
||
"required": true,
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/RegisterRequest" },
|
||
"example": {
|
||
"username": "newuser",
|
||
"password": "abc123"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "注册成功,自动登录返回双 Token",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"allOf": [
|
||
{ "$ref": "#/components/schemas/ApiResponse" },
|
||
{
|
||
"type": "object",
|
||
"properties": {
|
||
"data": { "$ref": "#/components/schemas/LoginResponse" }
|
||
}
|
||
}
|
||
]
|
||
},
|
||
"example": {
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": {
|
||
"accessToken": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||
"refreshToken": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"400": { "$ref": "#/components/responses/BadRequest" },
|
||
"500": { "$ref": "#/components/responses/InternalError" }
|
||
}
|
||
}
|
||
},
|
||
"/account/refresh": {
|
||
"post": {
|
||
"tags": ["账号"],
|
||
"summary": "刷新 Access Token",
|
||
"description": "当 Access Token 过期(30 分钟)后,使用 Refresh Token 换取新的 Access Token。Refresh Token 保持不变,仅在满 30 天或重新登录时更新。该接口无需登录即可调用。",
|
||
"operationId": "refresh",
|
||
"security": [],
|
||
"requestBody": {
|
||
"required": true,
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/RefreshTokenRequest" },
|
||
"example": {
|
||
"refreshToken": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "刷新成功,返回新的 Access Token 和原 Refresh Token",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"allOf": [
|
||
{ "$ref": "#/components/schemas/ApiResponse" },
|
||
{
|
||
"type": "object",
|
||
"properties": {
|
||
"data": { "$ref": "#/components/schemas/LoginResponse" }
|
||
}
|
||
}
|
||
]
|
||
},
|
||
"example": {
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": {
|
||
"accessToken": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
|
||
"refreshToken": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"400": { "$ref": "#/components/responses/BadRequest" },
|
||
"500": { "$ref": "#/components/responses/InternalError" }
|
||
}
|
||
}
|
||
},
|
||
"/user/info": {
|
||
"get": {
|
||
"tags": ["用户"],
|
||
"summary": "获取当前登录用户信息",
|
||
"description": "根据请求头中的 saToken(Access Token)获取当前登录用户的详细信息,包括昵称、头像、个性签名、年龄、性别、生日。需登录认证。",
|
||
"operationId": "getUserInfo",
|
||
"security": [{ "saToken": [] }],
|
||
"responses": {
|
||
"200": {
|
||
"description": "查询成功,返回用户信息",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"allOf": [
|
||
{ "$ref": "#/components/schemas/ApiResponse" },
|
||
{
|
||
"type": "object",
|
||
"properties": {
|
||
"data": { "$ref": "#/components/schemas/UserInfoResponse" }
|
||
}
|
||
}
|
||
]
|
||
},
|
||
"example": {
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": {
|
||
"nickName": "玩家001",
|
||
"avatar": "https://cdn.example.com/avatars/default.png",
|
||
"signature": "这个人很懒,什么都没写",
|
||
"age": 25,
|
||
"sex": 1,
|
||
"birthday": "2001-01-01"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": { "$ref": "#/components/responses/Unauthorized" },
|
||
"500": { "$ref": "#/components/responses/InternalError" }
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"components": {
|
||
"securitySchemes": {
|
||
"saToken": {
|
||
"type": "apiKey",
|
||
"in": "header",
|
||
"name": "saToken",
|
||
"description": "Access Token(登录/注册/刷新接口返回的 accessToken 值)。有效期 30 分钟,过期后使用 /account/refresh 接口获取新 Token。"
|
||
}
|
||
},
|
||
"schemas": {
|
||
"ApiResponse": {
|
||
"type": "object",
|
||
"description": "统一 API 响应信封。所有接口均使用此格式返回。",
|
||
"required": ["code", "message", "data"],
|
||
"properties": {
|
||
"code": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"description": "业务状态码。0 表示成功,非 0 表示失败。详细错误码见 ErrorCode 枚举。"
|
||
},
|
||
"message": {
|
||
"type": "string",
|
||
"description": "响应消息。成功时固定为 \"success\",失败时为具体错误描述。"
|
||
},
|
||
"data": {
|
||
"nullable": true,
|
||
"description": "响应数据负载。成功时携带对应的业务数据对象,失败时为 null。"
|
||
}
|
||
}
|
||
},
|
||
"LoginRequest": {
|
||
"type": "object",
|
||
"description": "登录请求体",
|
||
"required": ["username", "password"],
|
||
"properties": {
|
||
"username": {
|
||
"type": "string",
|
||
"description": "用户名,不能为空",
|
||
"minLength": 1,
|
||
"example": "testuser"
|
||
},
|
||
"password": {
|
||
"type": "string",
|
||
"format": "password",
|
||
"description": "密码,不能为空",
|
||
"minLength": 1,
|
||
"example": "123456"
|
||
}
|
||
}
|
||
},
|
||
"RegisterRequest": {
|
||
"type": "object",
|
||
"description": "注册请求体",
|
||
"required": ["username", "password"],
|
||
"properties": {
|
||
"username": {
|
||
"type": "string",
|
||
"description": "用户名,长度限制 3-32 位,不能为空",
|
||
"minLength": 3,
|
||
"maxLength": 32,
|
||
"example": "newuser"
|
||
},
|
||
"password": {
|
||
"type": "string",
|
||
"format": "password",
|
||
"description": "密码,长度限制 6-64 位,不能为空",
|
||
"minLength": 6,
|
||
"maxLength": 64,
|
||
"example": "abc123"
|
||
}
|
||
}
|
||
},
|
||
"RefreshTokenRequest": {
|
||
"type": "object",
|
||
"description": "刷新令牌请求体",
|
||
"required": ["refreshToken"],
|
||
"properties": {
|
||
"refreshToken": {
|
||
"type": "string",
|
||
"description": "刷新令牌,登录/注册时返回的 refreshToken 值,不能为空",
|
||
"minLength": 1,
|
||
"example": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
|
||
}
|
||
}
|
||
},
|
||
"LoginResponse": {
|
||
"type": "object",
|
||
"description": "登录、注册或刷新令牌成功时返回的认证令牌对",
|
||
"required": ["accessToken", "refreshToken"],
|
||
"properties": {
|
||
"accessToken": {
|
||
"type": "string",
|
||
"description": "Access Token(UUID 格式),有效期 30 分钟。后续请求需在 Header 中通过 saToken 字段携带此值。过期后使用 /account/refresh 接口刷新。",
|
||
"example": "12345678-1234-1234-1234-123456789abc"
|
||
},
|
||
"refreshToken": {
|
||
"type": "string",
|
||
"description": "Refresh Token(64 位十六进制随机字符串),有效期 30 天。仅用于 /account/refresh 接口换取新的 Access Token。刷新时不变,重新登录时替换。",
|
||
"example": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
|
||
}
|
||
}
|
||
},
|
||
"UserInfoResponse": {
|
||
"type": "object",
|
||
"description": "当前登录用户的详细信息",
|
||
"properties": {
|
||
"nickName": {
|
||
"type": "string",
|
||
"description": "用户昵称",
|
||
"maxLength": 16,
|
||
"example": "玩家001"
|
||
},
|
||
"avatar": {
|
||
"type": "string",
|
||
"description": "头像图片 URL 地址,可能为 null",
|
||
"maxLength": 512,
|
||
"nullable": true,
|
||
"example": "https://cdn.example.com/avatars/default.png"
|
||
},
|
||
"signature": {
|
||
"type": "string",
|
||
"description": "个性签名,可能为 null",
|
||
"maxLength": 64,
|
||
"nullable": true,
|
||
"example": "这个人很懒,什么都没写"
|
||
},
|
||
"age": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"description": "年龄,可能为 null",
|
||
"nullable": true,
|
||
"example": 25
|
||
},
|
||
"sex": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"description": "性别。1=男,2=女,可能为 null",
|
||
"nullable": true,
|
||
"enum": [1, 2],
|
||
"x-enum-descriptions": {
|
||
"1": "男",
|
||
"2": "女"
|
||
},
|
||
"example": 1
|
||
},
|
||
"birthday": {
|
||
"type": "string",
|
||
"format": "date",
|
||
"description": "生日(ISO 8601 日期格式),可能为 null",
|
||
"nullable": true,
|
||
"example": "2001-01-01"
|
||
}
|
||
}
|
||
},
|
||
"ErrorResponse": {
|
||
"type": "object",
|
||
"description": "错误响应体模板。code 为具体错误码,message 为错误描述,data 恒为 null。",
|
||
"required": ["code", "message", "data"],
|
||
"properties": {
|
||
"code": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"description": "错误码,详见 ErrorCode 枚举表"
|
||
},
|
||
"message": {
|
||
"type": "string",
|
||
"description": "人类可读的错误描述信息"
|
||
},
|
||
"data": {
|
||
"type": "null",
|
||
"description": "错误时恒为 null"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"BadRequest": {
|
||
"description": "请求参数校验失败或业务逻辑错误(HTTP 200 但 code ≠ 0)",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
||
"examples": {
|
||
"validation": {
|
||
"summary": "参数校验失败",
|
||
"value": {
|
||
"code": 400,
|
||
"message": "username 用户名不能为空; password 密码长度6-64位",
|
||
"data": null
|
||
}
|
||
},
|
||
"usernameExists": {
|
||
"summary": "用户名已存在",
|
||
"value": {
|
||
"code": 1001,
|
||
"message": "用户名已存在",
|
||
"data": null
|
||
}
|
||
},
|
||
"badCredentials": {
|
||
"summary": "用户名或密码错误",
|
||
"value": {
|
||
"code": 1002,
|
||
"message": "用户名或密码错误",
|
||
"data": null
|
||
}
|
||
},
|
||
"refreshTokenInvalid": {
|
||
"summary": "刷新令牌无效或已过期",
|
||
"value": {
|
||
"code": 1003,
|
||
"message": "刷新令牌无效或已过期",
|
||
"data": null
|
||
}
|
||
},
|
||
"refreshTokenMissing": {
|
||
"summary": "缺少刷新令牌",
|
||
"value": {
|
||
"code": 1004,
|
||
"message": "缺少刷新令牌",
|
||
"data": null
|
||
}
|
||
},
|
||
"userNotFound": {
|
||
"summary": "用户不存在",
|
||
"value": {
|
||
"code": 2001,
|
||
"message": "用户不存在",
|
||
"data": null
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"Unauthorized": {
|
||
"description": "未登录或 Access Token 无效/过期(HTTP 200 但 code=401)",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
||
"example": {
|
||
"code": 401,
|
||
"message": "请先登录",
|
||
"data": null
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"Forbidden": {
|
||
"description": "无权限或无角色访问(HTTP 200 但 code=403)",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
||
"example": {
|
||
"code": 403,
|
||
"message": "无权限",
|
||
"data": null
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"NotFound": {
|
||
"description": "请求的资源不存在",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
||
"example": {
|
||
"code": 404,
|
||
"message": "资源不存在",
|
||
"data": null
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"MethodNotAllowed": {
|
||
"description": "请求方法不支持(如 GET 访问 POST 接口)",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
||
"example": {
|
||
"code": 405,
|
||
"message": "请求方法不支持",
|
||
"data": null
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"InternalError": {
|
||
"description": "服务器内部错误(HTTP 200 但 code=5000)",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
||
"example": {
|
||
"code": 5000,
|
||
"message": "服务器内部错误",
|
||
"data": null
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"x-enums": {
|
||
"ErrorCode": {
|
||
"description": "业务错误码枚举(com.webgame.webgamebackend.common.exception.ErrorCode)",
|
||
"values": {
|
||
"SUCCESS": {
|
||
"code": 0,
|
||
"message": "success",
|
||
"description": "操作成功"
|
||
},
|
||
"BAD_REQUEST": {
|
||
"code": 400,
|
||
"message": "参数校验失败",
|
||
"description": "请求参数不符合校验规则"
|
||
},
|
||
"USERNAME_EXISTS": {
|
||
"code": 1001,
|
||
"message": "用户名已存在",
|
||
"description": "注册时用户名已被占用"
|
||
},
|
||
"BAD_CREDENTIALS": {
|
||
"code": 1002,
|
||
"message": "用户名或密码错误",
|
||
"description": "登录时用户名或密码不匹配"
|
||
},
|
||
"REFRESH_TOKEN_INVALID": {
|
||
"code": 1003,
|
||
"message": "刷新令牌无效或已过期",
|
||
"description": "Refresh Token 不存在或已过期(30 天),需重新登录"
|
||
},
|
||
"REFRESH_TOKEN_MISSING": {
|
||
"code": 1004,
|
||
"message": "缺少刷新令牌",
|
||
"description": "请求体中的 refreshToken 字段为空"
|
||
},
|
||
"USER_NOT_FOUND": {
|
||
"code": 2001,
|
||
"message": "用户不存在",
|
||
"description": "查询的用户记录不存在"
|
||
},
|
||
"INTERNAL_ERROR": {
|
||
"code": 5000,
|
||
"message": "服务器内部错误",
|
||
"description": "未预期的服务器异常"
|
||
}
|
||
}
|
||
},
|
||
"Sex": {
|
||
"description": "性别枚举(UserEntity.sex 字段)",
|
||
"values": {
|
||
"MALE": {
|
||
"code": 1,
|
||
"label": "男"
|
||
},
|
||
"FEMALE": {
|
||
"code": 2,
|
||
"label": "女"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} |