mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
2552 字
7 分钟
幽云 API调用
2026-05-16

幽云用户系统 API 接入文档#

面向第三方开发者的接入指南,涵盖注册、登录、Token 验证、房间管理的完整调用说明。


目录#


外部站点 API#

基本信息#

项目
接口地址https://api.yun52.cn/api/external.php
请求方式POST
Content-Typeapplication/json
认证方式请求头 X-API-Key: 你的API Key
字符编码UTF-8

获取 API Key#

API Key 是调用外部接口的必要凭证,由管理员在后台生成。

获取流程:

  1. 联系认证中心管理员
  2. 管理员登录后台 → 「API Key」页面 → 填写你的平台名称 → 生成 Key
  3. 管理员将生成的 Key(ak_ 开头的字符串)提供给你
  4. 在所有 API 请求的 Header 中携带:X-API-Key: ak_xxxxx...

注意事项:

  • 每个平台拥有独立的 Key,互不影响
  • 管理员可以随时禁用或重新生成你的 Key
  • Key 一旦重新生成,旧 Key 立即失效
  • 请妥善保管 Key,不要暴露在前端代码或公开仓库中

通用说明#

请求格式#

所有请求均为 POST,Body 为 JSON 格式:

{
"action": "接口名称",
"参数1": "值1",
"参数2": "值2"
}

响应格式#

所有接口返回统一 JSON 结构:

{
"success": true,
"message": "描述信息",
...其他字段
}

HTTP 状态码#

状态码含义
200请求已处理(需检查 success 字段判断业务是否成功)
401API Key 无效、缺失、或已被禁用
405请求方法不是 POST
429请求频率超限

接口列表#

1. 用户注册#

注册新用户,成功后自动返回登录 Token。

请求参数:

参数类型必填说明
actionstring固定值 "register"
usernamestring用户名,3-32 字符,仅支持字母、数字、下划线、中文
passwordstring密码,最少 6 个字符
extraany附加信息(可选),任意 JSON 值,最大 4KB

请求示例:

{
"action": "register",
"username": "zhangsan",
"password": "MyPass123!",
"extra": {
"source": "mobile_app",
"device_id": "ABC123",
"version": "2.0"
}
}

成功响应:

{
"success": true,
"message": "注册成功",
"token": "eyJhbGciOi...",
"username": "zhangsan"
}

失败响应:

{
"success": false,
"message": "用户名已被占用"
}

2. 用户登录#

验证用户名和密码,成功返回 Token。

请求参数:

参数类型必填说明
actionstring固定值 "login"
usernamestring用户名
passwordstring密码
extraany附加信息(可选),每次登录时可更新

请求示例:

{
"action": "login",
"username": "zhangsan",
"password": "MyPass123!",
"extra": {
"device": "iPhone 15",
"app_version": "3.1"
}
}

成功响应:

{
"success": true,
"message": "登录成功",
"token": "eyJhbGciOi...",
"username": "zhangsan"
}

失败响应:

{
"success": false,
"message": "用户名或密码错误"
}

🔒 无论用户名是否存在,失败时均返回相同错误信息(防枚举攻击)。


3. 验证 Token#

检查用户持有的 Token 是否有效。适用于页面刷新后校验登录状态。

请求参数:

参数类型必填说明
actionstring固定值 "verify"
tokenstring登录/注册时获得的 Token

成功响应:

{
"success": true,
"message": "Token 有效",
"valid": true,
"username": "zhangsan",
"expires": "2026-05-16T16:26:00+08:00"
}

失败响应:

{
"success": false,
"message": "Token 无效或已过期"
}

4. 检查用户名可用性#

在注册前提前检查用户名是否已被占用。

请求参数:

参数类型必填说明
actionstring固定值 "check"
usernamestring要检查的用户名

响应(用户名可用):

{
"success": true,
"message": "查询成功",
"available": true
}

响应(用户名已被占用):

{
"success": true,
"message": "查询成功",
"available": false
}

5. 修改密码#

已登录用户修改自己的密码,需要在请求中携带 Token。

请求参数:

参数类型必填说明
actionstring固定值 "change_password"
tokenstring登录/注册时获得的 Token
old_passwordstring当前密码
new_passwordstring新密码,最少 6 个字符

请求示例:

{
"action": "change_password",
"token": "eyJhbGciOi...",
"old_password": "MyPass123!",
"new_password": "NewPass456!"
}

成功响应:

{
"success": true,
"message": "密码修改成功"
}

失败响应:

{
"success": false,
"message": "当前密码错误"
}

🔒 修改密码后,当前 Token 仍然有效(不会被吊销),直到过期。


房间 API#

房间管理接口,支持创建、加入、踢人、消息等操作。

接口地址: https://api.yun52.cn/api/room.php 请求方式: POST,Body 为 JSON 认证方式: token 参数(前端 Token)或 X-API-Key 头 + token 参数(外部站点)


1. room_create — 创建房间#

请求参数:

参数类型必填说明
actionstring固定值 "room_create"
tokenstring登录 Token
namestring房间名(默认”{用户名}的房间”,最长 32 字符)
max_playersint最大人数(2-100,默认 4)
is_publicbool是否公开(默认 false)
passwordstring房间密码(空表示无密码,最长 64 字符)
extraany自定义附加数据(最大 4KB)

响应:

{"success": true, "room_id": "A1B2C3", "message": "房间创建成功"}

2. room_join — 加入房间#

请求参数:

参数类型必填说明
actionstring固定值 "room_join"
tokenstring登录 Token
room_idstring房间号(6 位大写十六进制)
passwordstring房间密码(有密码时必填)

失败响应:

{"success": false, "message": "房间不存在"}
{"success": false, "message": "房间已关闭或已开始"}
{"success": false, "message": "你已在该房间中"}
{"success": false, "message": "房间已满"}
{"success": false, "message": "房间密码错误"}

3. room_leave — 离开房间#

房主离开时:若房间还有人,自动转移房主;若无人,自动删除房间。

{"action": "room_leave", "token": "...", "room_id": "A1B2C3"}

4. room_list — 房间列表#

参数说明
filterall(默认) / waiting / playing / public
page页码(默认 1)
per_page每页数量(10-50,默认 20)

响应:

{
"success": true,
"rooms": [
{
"room_id": "A1B2C3",
"name": "测试房间",
"owner": "zhangsan",
"status": "waiting",
"is_public": true,
"has_password": false,
"player_count": 2,
"max_players": 4,
"create_time": 1777724669
}
],
"total": 1,
"page": 1,
"per_page": 20,
"total_pages": 1
}

5. room_info — 房间详情#

参数说明
room_id房间号

非成员只能查看公开房间。成员可看到消息记录。

响应:

{
"success": true,
"room": {
"room_id": "A1B2C3",
"name": "测试房间",
"owner": "zhangsan",
"status": "waiting",
"is_public": true,
"has_password": false,
"max_players": 4,
"members": [
{"username": "zhangsan", "role": "owner", "joined_at": "..."},
{"username": "lisi", "role": "member", "joined_at": "..."}
],
"messages": [...],
"message_count": 5,
"create_time": 1777724669,
"update_time": 1777724700,
"is_member": true,
"my_role": "owner",
"extra": {"game_type": "chess"}
}
}

6. room_update — 修改房间设置(仅房主)#

可更新字段:namemax_playersis_publicpasswordstatusextra

{"action": "room_update", "token": "...", "room_id": "A1B2C3", "name": "新名字", "status": "playing"}

7. room_kick — 踢出成员(仅房主)#

{"action": "room_kick", "token": "...", "room_id": "A1B2C3", "kick_username": "lisi"}

8. room_delete — 删除房间(仅房主)#

{"action": "room_delete", "token": "...", "room_id": "A1B2C3"}

9. room_message — 发送房间消息#

参数说明
room_id房间号
content消息内容(最大 500 字符)
typetext(默认) / emoji / event

消息保留最近 50 条,超出自动淘汰旧消息。


错误码与排错#

业务错误(HTTP 200,success: false#

错误消息原因解决方案
用户名不能为空请求中未传 username检查 JSON Body
用户名长度必须在 3-32 个字符之间用户名太短或太长调整用户名长度
用户名只能包含字母、数字、下划线和中文用户名包含特殊字符去除特殊字符
密码不能为空请求中未传 password检查 JSON Body
密码长度不能少于 6 个字符密码太短加长密码
用户名已被占用注册时用户名已存在换一个用户名,或用 check 接口预先查询
用户名或密码错误登录凭据不正确核对用户名和密码
Token 不能为空verify 请求未传 Token检查参数
Token 无效或已过期Token 不正确或超过有效期重新登录获取新 Token
新密码不能为空change_password 未传新密码检查 JSON Body
新密码不能与当前密码相同新旧密码一样使用不同密码
当前密码错误change_password 旧密码不正确核对当前密码
请先登录未传 Token携带有效 Token
附加信息过大(最大 4KB)extra 字段超过限制精简附加数据
房间不存在room 操作找不到房间检查 room_id
房间已满room_join 人数已满等待有人离开
房间密码错误room_join 密码不正确输入正确密码
仅房主可修改房间设置room_update 非房主操作只有房主能改
仅房主可踢出成员room_kick 非房主操作只有房主能踢人
你不在该房间中room_message 非成员先加入房间
未知 action: xxxaction 参数不在支持范围内检查拼写

HTTP 错误#

HTTP 状态码错误消息原因解决方案
401无效的 API KeyX-API-Key 缺失、错误、或已被禁用联系管理员确认 Key 状态
405仅支持 POST 方法使用了 GET 等其他方法改用 POST
429请求过于频繁,请稍后再试超过频率限制等待 60 秒后重试
400无效的 JSON 数据Body 不是合法 JSON检查 JSON 格式

调用示例#

cURL#

# 注册
curl -X POST "https://api.yun52.cn/api/external.php" \
-H "Content-Type: application/json" \
-H "X-API-Key: ak_xxxxx..." \
-d '{"action":"register","username":"zhangsan","password":"MyPass123!"}'
# 登录
curl -X POST "https://api.yun52.cn/api/external.php" \
-H "Content-Type: application/json" \
-H "X-API-Key: ak_xxxxx..." \
-d '{"action":"login","username":"zhangsan","password":"MyPass123!"}'
# 验证 Token
curl -X POST "https://api.yun52.cn/api/external.php" \
-H "Content-Type: application/json" \
-H "X-API-Key: ak_xxxxx..." \
-d '{"action":"verify","token":"eyJhbGciOi..."}'
# 检查用户名
curl -X POST "https://api.yun52.cn/api/external.php" \
-H "Content-Type: application/json" \
-H "X-API-Key: ak_xxxxx..." \
-d '{"action":"check","username":"lisi"}'
# 修改密码
curl -X POST "https://api.yun52.cn/api/external.php" \
-H "Content-Type: application/json" \
-H "X-API-Key: ak_xxxxx..." \
-d '{"action":"change_password","token":"eyJhbGciOi...","old_password":"OldPass!","new_password":"NewPass!"}'
# 创建房间
curl -X POST "https://api.yun52.cn/api/room.php" \
-H "Content-Type: application/json" \
-d '{"action":"room_create","token":"eyJhbGciOi...","name":"测试房间","max_players":4,"is_public":true}'
# 加入房间
curl -X POST "https://api.yun52.cn/api/room.php" \
-H "Content-Type: application/json" \
-d '{"action":"room_join","token":"eyJhbGciOi...","room_id":"A1B2C3"}'
# 房间列表
curl -X POST "https://api.yun52.cn/api/room.php" \
-H "Content-Type: application/json" \
-d '{"action":"room_list","token":"eyJhbGciOi...","filter":"public"}'
# 发送房间消息
curl -X POST "https://api.yun52.cn/api/room.php" \
-H "Content-Type: application/json" \
-d '{"action":"room_message","token":"eyJhbGciOi...","room_id":"A1B2C3","content":"你好"}'

JavaScript (fetch)#

const API_URL = 'https://api.yun52.cn/api/external.php';
const ROOM_URL = 'https://api.yun52.cn/api/room.php';
const API_KEY = 'ak_xxxxx...';
async function callAuth(action, params = {}) {
const res = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-API-Key': API_KEY },
body: JSON.stringify({ action, ...params }),
});
if (res.status === 401) throw new Error('API Key 无效');
if (res.status === 429) throw new Error('请求过于频繁');
const data = await res.json();
if (!data.success) throw new Error(data.message);
return data;
}
async function roomApi(action, params = {}) {
const token = localStorage.getItem('auth_token');
const res = await fetch(ROOM_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action, token, ...params }),
});
const data = await res.json();
if (!data.success) throw new Error(data.message);
return data;
}
// 外部 API
await callAuth('register', { username: 'zhangsan', password: 'MyPass123!' });
await callAuth('login', { username: 'zhangsan', password: 'MyPass123!' });
await callAuth('verify', { token: '...' });
await callAuth('check', { username: 'lisi' });
await callAuth('change_password', { token: '...', old_password: 'Old!', new_password: 'New!' });
// 房间 API
await roomApi('room_create', { name: '我的房间', max_players: 4, is_public: true });
await roomApi('room_join', { room_id: 'A1B2C3' });
const { rooms } = await roomApi('room_list', { filter: 'public' });
await roomApi('room_message', { room_id: 'A1B2C3', content: '你好' });

Python (requests)#

import requests
API_URL = "https://api.yun52.cn/api/external.php"
ROOM_URL = "https://api.yun52.cn/api/room.php"
API_KEY = "ak_xxxxx..."
headers = {"Content-Type": "application/json", "X-API-Key": API_KEY}
def call_auth(action, **params):
r = requests.post(API_URL, json={"action": action, **params}, headers=headers, timeout=10)
if r.status_code == 401: raise Exception("API Key 无效")
data = r.json()
if not data.get("success"): raise Exception(data.get("message", "未知错误"))
return data
def room_api(action, token, **params):
r = requests.post(ROOM_URL, json={"action": action, "token": token, **params}, headers=headers, timeout=10)
data = r.json()
if not data.get("success"): raise Exception(data.get("message", "未知错误"))
return data
# 外部 API
call_auth("register", username="zhangsan", password="MyPass123!")
call_auth("login", username="zhangsan", password="MyPass123!")
call_auth("verify", token="eyJ...")
call_auth("check", username="lisi")
call_auth("change_password", token="eyJ...", old_password="Old!", new_password="New!")
# 房间 API
room_api("room_create", token="eyJ...", name="测试房间", max_players=4, is_public=True)
room_api("room_join", token="eyJ...", room_id="A1B2C3")
room_api("room_list", token="eyJ...", filter="public")
room_api("room_message", token="eyJ...", room_id="A1B2C3", content="你好")

PHP (cURL)#

<?php
define('API_URL', 'https://api.yun52.cn/api/external.php');
define('ROOM_URL', 'https://api.yun52.cn/api/room.php');
define('API_KEY', 'ak_xxxxx...');
function callAuth(string $action, array $params = []): array {
$ch = curl_init(API_URL);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(array_merge(['action' => $action], $params)),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-API-Key: ' . API_KEY],
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 401) throw new Exception('API Key 无效');
$data = json_decode($response, true);
if (!$data || !$data['success']) throw new Exception($data['message'] ?? '未知错误');
return $data;
}
function roomApi(string $action, string $token, array $params = []): array {
$ch = curl_init(ROOM_URL);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(array_merge(['action' => $action, 'token' => $token], $params)),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
if (!$data || !$data['success']) throw new Exception($data['message'] ?? '未知错误');
return $data;
}
// 外部 API
callAuth('register', ['username' => 'zhangsan', 'password' => 'MyPass123!']);
callAuth('login', ['username' => 'zhangsan', 'password' => 'MyPass123!']);
callAuth('verify', ['token' => $token]);
callAuth('change_password', ['token' => $token, 'old_password' => 'Old!', 'new_password' => 'New!']);
// 房间 API
roomApi('room_create', $token, ['name' => '测试房间', 'max_players' => 4, 'is_public' => true]);
roomApi('room_join', $token, ['room_id' => 'A1B2C3']);

Node.js (axios)#

const axios = require('axios');
const API_URL = 'https://api.yun52.cn/api/external.php';
const ROOM_URL = 'https://api.yun52.cn/api/room.php';
const API_KEY = 'ak_xxxxx...';
async function callAuth(action, params = {}) {
const { data } = await axios.post(API_URL, { action, ...params }, {
headers: { 'Content-Type': 'application/json', 'X-API-Key': API_KEY },
timeout: 10000,
});
if (!data.success) throw new Error(data.message);
return data;
}
async function roomApi(action, token, params = {}) {
const { data } = await axios.post(ROOM_URL, { action, token, ...params }, {
headers: { 'Content-Type': 'application/json' },
timeout: 10000,
});
if (!data.success) throw new Error(data.message);
return data;
}
// 外部 API
await callAuth('register', { username: 'zhangsan', password: 'MyPass123!' });
await callAuth('login', { username: 'zhangsan', password: 'MyPass123!' });
await callAuth('verify', { token: 'eyJ...' });
await callAuth('change_password', { token: 'eyJ...', old_password: 'Old!', new_password: 'New!' });
// 房间 API
await roomApi('room_create', token, { name: '测试房间', max_players: 4, is_public: true });
await roomApi('room_join', token, { room_id: 'A1B2C3' });

Token 使用指南#

Token 生命周期#

阶段说明
获取注册或登录成功后由服务端返回
存储前端存 localStorage / 后端存 SessionHttpOnly Cookie
验证调用 verify 接口检查有效性
过期过期后重新登录获取新 Token
有效期默认 24 小时(管理员可在后台调整)

建议的前端存储方式#

方式安全性适用场景
localStorage中等简单 SPA
HttpOnly Cookie生产环境推荐
SessionStorage中等关闭标签页自动清除

最佳实践#

注册流程#

用户输入用户名 → [check 接口] → 用户输入密码 → [register 接口] → 存储 Token → 跳转首页

登录流程#

用户输入凭据 → [login 接口] → 成功存 Token → 跳转
→ 失败提示(不要暗示是用户名还是密码错)

登录状态保持#

页面加载 → 读取 Token → [verify 接口]
→ 有效:显示已登录
→ 无效:清除 Token,跳转登录

错误处理#

try {
const result = await callAuth('login', { username, password });
} catch (e) {
if (e.message.includes('频繁')) {
// 提示用户等待
} else if (e.message.includes('API Key')) {
// Key 问题,联系管理员
} else {
// 展示业务错误
}
}

常见问题 FAQ#

Q: 为什么登录失败不说”用户名不存在”还是”密码错误”?#

安全考虑。统一流报防止攻击者枚举已注册用户名。

Q: API Key 丢了怎么办?#

联系管理员在后台重新生成。旧 Key 立即失效,新 Key 需更新到你的代码中。

Q: API Key 被禁用了会怎样?#

所有携带该 Key 的请求将返回 401 Unauthorized。联系管理员启用。

Q: Token 过期了怎么办?#

重新调用 login 接口获取新 Token。有效期默认 24 小时,管理员可调整。

Q: 密码有要求吗?#

最少 6 个字符,最长 128 个字符(管理员可调整范围)。

Q: 用户名支持哪些字符?#

字母(a-z, A-Z)、数字(0-9)、下划线(_)、中文。长度 3-32 字符(管理员可调整)。

Q: 超过频率限制怎么办?#

返回 429 状态码,等待 60 秒后自动恢复。建议前端做指数退避重试。

Q: 如何获取 API Key?#

联系认证中心管理员,在后台「API Key」页面生成后提供给你。

Q: extra 字段是什么?#

extra 是一个可选的附加信息字段,你可以在注册或登录时传入任意 JSON 值(如设备信息、来源渠道、版本号等),系统会将其保存到用户数据中。每次登录时传入新的 extra 会覆盖之前的值。管理员可在后台查看每个用户的 extra 数据。

Q: 如何修改密码?#

调用 change_password 接口,需要携带当前登录的 Token、当前密码和新密码。详见接口文档中的「修改密码」章节。

Q: 房间 API 怎么用?#

房间 API 需要用户先登录获取 Token,然后通过 /api/room.php 调用。支持创建、加入、踢人、发消息等操作。房间号为 6 位大写十六进制(如 A1B2C3)。房主离开时自动转移房主,无人时自动删除房间。详见「房间 API」章节。

Q: 房间密码安全吗?#

房间密码使用 bcrypt 哈希存储(cost=8),与用户密码同样安全。加入时需要输入正确密码。

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

幽云 API调用
https://youzix.top/posts/api/
作者
洛轻羽
发布于
2026-05-16
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录