远程管理 API 参考
HeartbeatSocks 内置 REST API 服务,用于远程管理 SOCKS5 账号和查询用户信息。API 兼容 CCProxy ProxyAccount_Controller 接口规范。
总览
┌─────────────────────────────────────────────────────────────────┐
│ 远程管理 API 架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 客户端请求 ──▶ IP 白名单检查 ──▶ Basic Auth 认证 ──▶ 路由分发 │
│ │ │ │ │
│ 拒绝 403 拒绝 401 端点处理 │
│ │ │
│ ┌───────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ /ProxyAccount │ │
│ │ ├── GET /GetProxyAccountList 获取所有账号 │ │
│ │ ├── GET /GetProxyAccountByID 获取指定账号 │ │
│ │ ├── POST /AddProxyAccount 添加账号 │ │
│ │ ├── POST /UpdateProxyAccount 更新账号 │ │
│ │ ├── POST /DeleteProxyAccount 删除账号(含级联删除) │ │
│ │ └── GET /GetCurrentUser 获取当前用户(免认证) │ │
│ │ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ 技术栈: ASP.NET Core Minimal API + Kestrel │
│ 数据格式: JSON │
│ 认证方式: HTTP Basic Authentication │
│ │
└─────────────────────────────────────────────────────────────────┘
基础信息
Base URL
http://{绑定IP}:{端口}
默认: http://localhost:8080
认证方式
API 使用 HTTP Basic Authentication,需要在请求的 Authorization Header 中携带 Base64 编码的管理员凭证。
Authorization: Basic {base64(username:password)}
示例(用户名 admin,密码 123456):
Authorization: Basic YWRtaW46MTIzNDU2
/ProxyAccount/GetCurrentUser 端点 不需要 Basic Auth 认证,它通过 X-Socks5-Username HTTP Header 识别用户身份。
安全机制
| 机制 | 说明 |
|---|---|
| IP 白名单 | 配置后仅允许白名单中的 IP 访问,支持通配符(如 192.168.1.*) |
| Basic Auth | 除 GetCurrentUser 外所有端点都需要管理员认证 |
| 密码哈希 | 管理员密码和账号密码均以 SHA256 哈希存储 |
| 暴力破解防护 | 认证失败时服务端延迟响应(500-1500ms 随机) |
| 内网限制 | GetCurrentUser 仅允许本地/内网 IP 访问 |
请求/响应格式
- Content-Type:
application/json - 编码: UTF-8
- 日期格式: ISO 8601(如
2025-01-01T00:00:00) - ID 格式: Guid(兼容 CCProxy,内部通过
GuidHelper与 int ID 互转)
端点详情
1. 获取所有账号
获取系统中所有 SOCKS5 账号列表,包含每个账号在数据池中的统计信息。
GET /ProxyAccount/GetProxyAccountList
认证: 需要 Basic Auth
请求参数: 无
响应: 200 OK
[
{
"AID": "00000000-0000-0000-0000-000000000001",
"Username": "player1",
"IsEnabled": true,
"Remarks": "测试账号",
"CreatedAt": "2025-01-15T08:30:00",
"LastLoginAt": "2025-06-01T14:22:33",
"ExpiresAt": null,
"DataCount": 152,
"LatestGameId": "A1B2C3D4E5"
},
{
"AID": "00000000-0000-0000-0000-000000000002",
"Username": "player2",
"IsEnabled": false,
"Remarks": "已停用",
"CreatedAt": "2025-02-20T10:00:00",
"LastLoginAt": "2025-05-15T09:10:00",
"ExpiresAt": "2025-12-31T23:59:59",
"DataCount": 0,
"LatestGameId": null
}
]
响应字段:
| 字段 | 类型 | 说明 |
|---|---|---|
AID | Guid | 账号唯一标识(CCProxy 兼容格式) |
Username | string | 用户名 |
IsEnabled | bool | 是否启用 |
Remarks | string? | 备注信息 |
CreatedAt | DateTime | 创建时间 |
LastLoginAt | DateTime? | 最后登录时间(未登录则为 null) |
ExpiresAt | DateTime? | 过期时间(null 表示永不过期) |
DataCount | int | 该账号在数据池中的心跳数据条数 |
LatestGameId | string? | 该账号最近采集的 GameID |
错误响应:
| 状态码 | 说明 |
|---|---|
401 Unauthorized | 认证失败 |
403 Forbidden | IP 不在白名单中 |
500 Internal Server Error | 服务器内部错误 |
2. 获取指定账号
通过账号 ID 获取单个账号的详细信息和数据池统计。
GET /ProxyAccount/GetProxyAccountByID?AID={guid}
认证: 需要 Basic Auth
查询参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
AID | Guid | 是 | 账号唯一标识 |
请求示例:
GET /ProxyAccount/GetProxyAccountByID?AID=00000000-0000-0000-0000-000000000001
响应: 200 OK
{
"AID": "00000000-0000-0000-0000-000000000001",
"Username": "player1",
"IsEnabled": true,
"Remarks": "测试账号",
"CreatedAt": "2025-01-15T08:30:00",
"LastLoginAt": "2025-06-01T14:22:33",
"ExpiresAt": null,
"DataCount": 152,
"LatestGameId": "A1B2C3D4E5"
}
错误响应:
| 状态码 | 说明 |
|---|---|
400 Bad Request | 无效的账号 ID 格式 |
404 Not Found | 账号不存在 |
3. 添加账号
创建新的 SOCKS5 代理账号。
POST /ProxyAccount/AddProxyAccount
认证: 需要 Basic Auth
请求体:
{
"Username": "new_player",
"Password": "my_secure_password",
"IsEnabled": true,
"Remarks": "新用户",
"ExpiresAt": "2026-12-31T23:59:59"
}
请求字段:
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
Username | string | 是 | — | 用户名(必须唯一) |
Password | string | 是 | — | 密码(明文传输,服务端以 SHA256 哈希存储) |
IsEnabled | bool | 否 | true | 是否启用 |
Remarks | string? | 否 | null | 备注信息 |
ExpiresAt | DateTime? | 否 | null | 过期时间(null = 永不过期) |
成功响应: 200 OK
"添加账号成功"
错误响应:
| 状态码 | 说明 |
|---|---|
400 Bad Request | 用户名或密码为空、用户名已存在 |
业务规则:
- 用户名不能为空,且必须唯一
- 密码不能为空
- 密码自动使用 SHA256 哈希后存储
- 创建时间自动设为当前 UTC 时间
4. 更新账号
修改已有账号的信息。
POST /ProxyAccount/UpdateProxyAccount
认证: 需要 Basic Auth
此端点使用 POST 而非 PUT,以兼容 CCProxy API 规范。
请求体:
{
"AID": "00000000-0000-0000-0000-000000000001",
"Password": "new_password",
"IsEnabled": true,
"Remarks": "更新后的备注",
"ExpiresAt": null
}
请求字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
AID | Guid | 是 | 要更新的账号 ID |
Password | string | 否 | 新密码(留空或不填则不修改密码) |
IsEnabled | bool | 否 | 是否启用 |
Remarks | string? | 否 | 备注 |
ExpiresAt | DateTime? | 否 | 过期时间 |
成功响应: 200 OK
"更新账号成功"
错误响应:
| 状态码 | 说明 |
|---|---|
400 Bad Request | 账号 ID 为空、无效的 ID 格式、账号不存在 |
业务规则:
Password为空或仅包含空白字符时不修改密码IsEnabled、Remarks、ExpiresAt总是会被更新(即使未提供也会使用默认值)
5. 删除账号
删除指定账号及其所有关联数据。
POST /ProxyAccount/DeleteProxyAccount?AID={guid}
认证: 需要 Basic Auth
此端点使用 POST 而非 DELETE,以兼容 CCProxy API 规范。
查询参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
AID | Guid | 是 | 要删除的账号 ID |
请求示例:
POST /ProxyAccount/DeleteProxyAccount?AID=00000000-0000-0000-0000-000000000001
成功响应: 200 OK
"删除账号成功"
错误响应:
| 状态码 | 说明 |
|---|---|
400 Bad Request | 无效的 ID 格式、账号不存在 |
删除账号时会同时删除该账号在数据池中的所有心跳数据(包括内存和数据库中的数据)。此操作不可逆。
级联删除流程:
- 从数据库删除该用户名关联的所有心跳数据
- 从内存数据池中移除该用户名的所有数据
- 删除账号本身
6. 获取当前用户
通过 HTTP Header 中的用户名获取当前 SOCKS5 认证用户的信息。此端点专为客户端应用设计,用于查询自身账号状态。
GET /ProxyAccount/GetCurrentUser
认证: 不需要 Basic Auth(通过 HTTP Header 识别用户)
请求 Header:
| Header | 必填 | 说明 |
|---|---|---|
X-Socks5-Username | 是 | SOCKS5 认证的用户名 |
请求示例:
GET /ProxyAccount/GetCurrentUser
X-Socks5-Username: player1
成功响应: 200 OK
{
"Username": "player1",
"IsEnabled": true,
"CreatedAt": "2025-01-15T08:30:00",
"LastLoginAt": "2025-06-01T14:22:33",
"ExpiresAt": null,
"IsExpired": false,
"DataCount": 152,
"LatestGameId": "A1B2C3D4E5"
}
响应字段:
| 字段 | 类型 | 说明 |
|---|---|---|
Username | string | 用户名 |
IsEnabled | bool | 是否启用 |
CreatedAt | DateTime | 创建时间 |
LastLoginAt | DateTime? | 最后登录时间 |
ExpiresAt | DateTime? | 过期时间(null = 永不过期) |
IsExpired | bool | 当前是否已过期 |
DataCount | int | 该用户在数据池中的心跳数据条数 |
LatestGameId | string? | 最近采集的 GameID |
错误响应:
| 状态码 | 说明 |
|---|---|
401 Unauthorized | 缺少 X-Socks5-Username Header |
403 Forbidden | 来源 IP 不是本地或内网地址 |
404 Not Found | 用户不存在 |
安全限制:
- 仅允许以下 IP 范围访问:
127.0.0.0/8(回环地址)10.0.0.0/8(A 类私有地址)172.16.0.0/12(B 类私有地址)192.168.0.0/16(C 类私有地址)fc00::/7(IPv6 唯一本地地址)fe80::/10(IPv6 链路本地地址)
端点总表
| 方法 | 路径 | 认证 | 说明 |
|---|---|---|---|
GET | /ProxyAccount/GetProxyAccountList | Basic Auth | 获取所有账号列表(含数据池统计) |
GET | /ProxyAccount/GetProxyAccountByID?AID={guid} | Basic Auth | 获取单个账号详情 |
POST | /ProxyAccount/AddProxyAccount | Basic Auth | 创建新账号 |
POST | /ProxyAccount/UpdateProxyAccount | Basic Auth | 更新账号信息 |
POST | /ProxyAccount/DeleteProxyAccount?AID={guid} | Basic Auth | 删除账号(含级联删除数据) |
GET | /ProxyAccount/GetCurrentUser | Header | 获取当前 SOCKS5 用户信息 |
使用示例
cURL
获取所有账号:
curl -u admin:password123 \
http://localhost:8080/ProxyAccount/GetProxyAccountList
添加账号:
curl -u admin:password123 \
-X POST \
-H "Content-Type: application/json" \
-d '{"Username":"player1","Password":"pass123","IsEnabled":true,"Remarks":"新用户"}' \
http://localhost:8080/ProxyAccount/AddProxyAccount
更新账号:
curl -u admin:password123 \
-X POST \
-H "Content-Type: application/json" \
-d '{"AID":"00000000-0000-0000-0000-000000000001","IsEnabled":false,"Remarks":"已停用"}' \
http://localhost:8080/ProxyAccount/UpdateProxyAccount
删除账号:
curl -u admin:password123 \
-X POST \
"http://localhost:8080/ProxyAccount/DeleteProxyAccount?AID=00000000-0000-0000-0000-000000000001"
获取当前用户(仅限本地/内网):
curl -H "X-Socks5-Username: player1" \
http://localhost:8080/ProxyAccount/GetCurrentUser
PowerShell
# 设置认证
$cred = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("admin:password123"))
$headers = @{ Authorization = "Basic $cred" }
# 获取所有账号
Invoke-RestMethod -Uri "http://localhost:8080/ProxyAccount/GetProxyAccountList" `
-Headers $headers
# 添加账号
$body = @{
Username = "player1"
Password = "pass123"
IsEnabled = $true
Remarks = "新用户"
} | ConvertTo-Json
Invoke-RestMethod -Uri "http://localhost:8080/ProxyAccount/AddProxyAccount" `
-Method Post -Headers $headers -ContentType "application/json" -Body $body
C# HttpClient
using var client = new HttpClient();
// 设置 Basic Auth
var credentials = Convert.ToBase64String(
Encoding.UTF8.GetBytes("admin:password123"));
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Basic", credentials);
// 获取所有账号
var response = await client.GetAsync(
"http://localhost:8080/ProxyAccount/GetProxyAccountList");
var accounts = await response.Content
.ReadFromJsonAsync<List<AccountResponse>>();
// 添加账号
var request = new
{
Username = "player1",
Password = "pass123",
IsEnabled = true,
Remarks = "新用户"
};
await client.PostAsJsonAsync(
"http://localhost:8080/ProxyAccount/AddProxyAccount", request);
错误处理
通用 HTTP 状态码
| 状态码 | 说明 | 常见原因 |
|---|---|---|
200 OK | 操作成功 | — |
400 Bad Request | 请求参数错误 | 缺少必填字段、ID 格式无效、用户名重复 |
401 Unauthorized | 认证失败 | 未提供凭证、用户名或密码错误 |
403 Forbidden | 访问被拒绝 | IP 不在白名单中、外网访问受限端点 |
404 Not Found | 资源不存在 | 账号 ID 不存在、用户名不存在 |
500 Internal Server Error | 服务器错误 | 数据库异常、内部处理失败 |
错误响应格式
错误信息以纯字符串返回(兼容 CCProxy):
"用户名和密码不能为空"
"该用户名已存在"
IP 白名单配置
在「系统配置」页面的 IP 白名单字段中配置允许访问 API 的 IP 地址。
格式
多个 IP 用逗号分隔:
192.168.1.100, 192.168.1.101, 10.0.0.50
支持通配符
192.168.1.* # 匹配 192.168.1.0/24 段
10.* # 匹配 10.0.0.0/8 段
* # 允许所有 IP(等同于不配置白名单)
注意事项
- 白名单为空时,允许所有 IP 访问
- 支持 IPv4 和 IPv6 地址
- IPv4-mapped IPv6 地址(如
::ffff:192.168.1.100)会自动转换为 IPv4 格式匹配 - 配置变更后无需重启 API 服务,下次请求立即生效(使用内部缓存优化性能)