{ "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": "女" } } } } } }