# API 参考 所有 `/api` 路径(除 `/login`、`/health`)都需要鉴权。 ## 鉴权 登录获取 JWT token(12 小时有效期): ```http POST /api/login Content-Type: application/json {"username": "admin", "password": "admin123"} ``` 成功响应: ```json {"token": "eyJhbG...", "username": "admin"} ``` 后续请求携带: ``` Authorization: Bearer ``` 下载 `.ovpn` 也支持通过 query 携带 token: ``` GET /api/instances//users//ovpn?host=vpn.example.com&token= ``` ## 通用响应 成功返回 JSON 对象或数组;失败: ```json {"error": "错误描述"} ``` HTTP 状态码:`200`/`400`/`401`/`404`/`500`。 --- ## 1. 公共 ### 健康检查 ``` GET /api/health → 200 {"ok": true} ``` ### 登录 ``` POST /api/login Content-Type: application/json {"username": "admin", "password": "..."} → 200 { "token": "eyJhbG...", "username": "admin", "role": "admin", "must_change_password": false } → 401 {"error": "用户名或密码错误"} → 403 {"error": "账号已被禁用"} ``` > 密码以 bcrypt 哈希存储在 `data/db.json` 中。 > `must_change_password=true` 表示首次登录(默认账号)需要立刻改密。 ### 当前登录账号 ``` GET /api/me → 200 { "user_id": "uuid", "username": "admin", "role": "admin", "must_change_password": false } ``` ### 修改自己密码 ``` POST /api/me/password {"old_password": "...", "new_password": "..."} → 200 {"ok": true} → 400 {"error": "原密码错误"} | {"error": "新密码至少 6 个字符"} ``` ### 登出(前端清理 token) ``` POST /api/logout → 200 {"ok": true} ``` --- ## 2. 管理员账号管理 > 仅 admin role 可访问。operator 访问会拒绝(由前端路由守卫 + 后端 handler 校验)。 ### 列出账号(不含 hash) ``` GET /api/admins → 200 [AdminUser, ...] // PasswordHash 字段固定为空 ``` ### 新建账号 ``` POST /api/admins {"username": "alice", "password": "StrongPass123", "role": "operator"} → 200 AdminUser ``` ### 重置密码(无需知道旧密码) ``` POST /api/admins/:id/password {"new_password": "NewPass456"} → 200 {"ok": true} ``` ### 启用/禁用 ``` POST /api/admins/:id/status {"status": "active"} | {"status": "disabled"} → 200 {"ok": true} ``` ### 删除(不能删自己、不能删最后一个 admin) ``` DELETE /api/admins/:id → 200 {"ok": true} → 400 {"error": "不能删除自己"} → 400 {"error": "不能删除最后一个 admin 账号"} ``` --- ## 3. 仪表盘 ### 汇总 ``` GET /api/dashboard → 200 { "instances": 2, "running": 1, "users": 10, "active_users": 9, "online": 3, "expiring_certs": 1, "recent_audits": [...], "recent_conn_logs": [...] } ``` --- ## 3. 实例 ### 列表 ``` GET /api/instances → 200 [Instance, ...] ``` ### 详情 ``` GET /api/instances/:id → 200 Instance → 404 {"error": "instance not found"} ``` ### 新建 ``` POST /api/instances { "name": "prod", "port": 1194, "proto": "udp", // udp | tcp "dev": "tun", // tun | tap "subnet": "10.8.0.0/24", "cipher": "AES-256-GCM", // 可选 "auth_digest": "SHA256", // 可选 "push_dns": "dhcp-option DNS 8.8.8.8\ndhcp-option DNS 1.1.1.1", "push_routes": "192.168.1.0 255.255.255.0", "extra": "", "access_mode": "whitelist", // open(默认) | whitelist "allow_networks": ["192.168.1.0/24", "10.0.0.0/8"] // CIDR 列表 } → 200 Instance ``` > `access_mode=whitelist` 时,服务端会生成 `client-connect.sh` / `client-disconnect.sh`, > 通过 OpenVPN `--learn-address` 钩子在每次客户端连接/断开时修改 iptables FORWARD 链, > 仅放行到 allow_networks 中网段的流量,其他内网访问被 REJECT。 > allow_networks 为空表示完全隔离(最严格)。 ### 更新 ``` PUT /api/instances/:id {...同上,id 在 URL 中} → 200 Instance ``` > 修改实例级 `allow_networks` 后,所有用户的 ccd 文件会被自动重写。 ### 删除(级联删除该实例下所有用户/证书) ``` DELETE /api/instances/:id → 200 {"ok": true} ``` ### 启动 ``` POST /api/instances/:id/start → 200 {"ok": true} ``` ### 停止 ``` POST /api/instances/:id/stop → 200 {"ok": true} ``` ### 在线客户端(来自 status-version 3) ``` GET /api/instances/:id/online → 200 [ { "CommonName": "alice", "RealAddress": "203.0.113.10:54321", "VPNAddress": "10.8.0.10", "BytesRecv": 12345, "BytesSent": 6789, "ConnectedAt": "2026-08-09T12:34:56Z" } ] ``` --- ## 4. 用户 ### 列表(可选按实例过滤) ``` GET /api/instances/:id/users → 200 [VPNUser, ...] ``` ### 新建(自动签发证书) ``` POST /api/instances/:id/users { "username": "alice", "real_name": "Alice", "email": "alice@example.com", "static_ip": "10.8.0.10", // 可选 "allow_networks": ["172.16.0.0/16"] // 可选,用户级白名单(在实例基础上叠加) } → 200 VPNUser ``` ### 修改(改 allow_networks / static_ip 等) ``` PUT /api/instances/:id/users/:uid {...同上} → 200 VPNUser ``` > 修改用户的 `allow_networks` 后,会重新生成 ccd 文件, > 用户重新连接即可拿到新的 push route。 ### 吊销 ``` POST /api/instances/:id/users/:uid/revoke → 200 {"ok": true} ``` ### 删除(同时删除证书与 .ovpn) ``` DELETE /api/instances/:id/users/:uid → 200 {"ok": true} ``` ### 下载客户端配置 ``` GET /api/instances/:id/users/:uid/ovpn?host=vpn.example.com → 200 application/octet-stream (.ovpn 文件) ``` --- ## 5. 证书 ### 到期清单 ``` GET /api/certs → 200 [ { "instance_id": "uuid", "username": "alice", "not_before": "2026-08-09T00:00:00Z", "not_after": "2036-08-06T00:00:00Z", "days_left": 3649 } ] ``` `days_left < 0` 表示已过期,`< 30` 在仪表盘会显示为"即将到期"。 --- ## 6. 连接日志 ``` GET /api/connlogs?instance= → 200 [ConnectionLog, ...] ``` 每条: ```json { "instance_id": "uuid", "common_name": "alice", "real_ip": "203.0.113.10:54321", "vpn_ip": "10.8.0.10", "bytes_in": 12345, "bytes_out": 6789, "connected_at": "...", "disconnected_at": null } ``` --- ## 7. 备份 ### 列表 ``` GET /api/backups → 200 [Backup, ...] ``` ### 创建 ``` POST /api/backups {"note": "before upgrade"} → 200 Backup ``` ### 恢复(覆盖现有数据) ``` POST /api/backups/:id/restore → 200 {"ok": true} ``` ### 删除 ``` DELETE /api/backups/:id → 200 {"ok": true} ``` --- ## 8. 审计 ``` GET /api/audits → 200 [AuditLog, ...] // 最近 500 条,倒序 ``` 每条: ```json { "id": "uuid", "time": "2026-08-09T12:34:56Z", "user": "admin", "action": "create_user", "target": "alice", "result": "ok", "detail": "instance=", "ip": "127.0.0.1" } ``` 可能的 action:`create_instance` / `update_instance` / `delete_instance` / `start_instance` / `stop_instance` / `create_user` / `revoke_user` / `delete_user` / `create_backup` / `restore_backup`。 --- ## 数据模型 ### Instance ```json { "id": "uuid", "name": "prod", "port": 1194, "proto": "udp", "dev": "tun", "subnet": "10.8.0.0/24", "cipher": "AES-256-GCM", "auth_digest": "SHA256", "push_dns": "...", "push_routes": "...", "extra": "", "access_mode": "open | whitelist", "allow_networks": ["192.168.1.0/24", "10.0.0.0/8"], "status": "running | stopped | error", "pid": 12345, "created_at": "...", "updated_at": "..." } ``` ### VPNUser ```json { "id": "uuid", "instance_id": "uuid", "username": "alice", "real_name": "Alice", "email": "alice@example.com", "enabled": true, "static_ip": "10.8.0.10", "allow_networks": ["172.16.0.0/16"], "created_at": "...", "revoked_at": null } ``` ### Backup ```json { "id": "uuid", "created_at": "...", "size": 12345, "note": "...", "filename": "backup-20260809-123456-abcd1234.tar.gz", "includes": ["pki", "instances", "clients"] } ``` --- ## curl 示例 完整流程(假设服务在 `http://localhost:8089`): ```bash # 1. 登录 TOKEN=$(curl -s -X POST http://localhost:8089/api/login \ -H 'content-type: application/json' \ -d '{"username":"admin","password":"admin123"}' | jq -r .token) # 2. 创建实例 curl -s -X POST http://localhost:8089/api/instances \ -H "Authorization: Bearer $TOKEN" \ -H 'content-type: application/json' \ -d '{ "name":"prod", "port":1194, "proto":"udp", "dev":"tun", "subnet":"10.8.0.0/24", "cipher":"AES-256-GCM", "auth_digest":"SHA256", "push_dns":"dhcp-option DNS 1.1.1.1" }' # 3. 创建用户 IID=$(curl -s http://localhost:8089/api/instances \ -H "Authorization: Bearer $TOKEN" | jq -r '.[0].id') curl -s -X POST http://localhost:8089/api/instances/$IID/users \ -H "Authorization: Bearer $TOKEN" \ -H 'content-type: application/json' \ -d '{"username":"alice","email":"alice@example.com"}' # 4. 拿 .ovpn UID=$(curl -s http://localhost:8089/api/instances/$IID/users \ -H "Authorization: Bearer $TOKEN" | jq -r '.[0].id') curl -s -o alice.ovpn \ "http://localhost:8089/api/instances/$IID/users/$UID/ovpn?host=vpn.example.com" \ -H "Authorization: Bearer $TOKEN" ``` --- ## 错误码 | HTTP | 含义 | | ---- | ---- | | 400 | 请求参数错误或操作失败(响应体有 `error` 字段) | | 401 | 未登录或 token 无效/过期 | | 404 | 资源不存在 | | 500 | 服务器内部错误 | --- ## 限制 - 单实例:Web 管理界面并发 100+ 连接无压力 - 单实例 OpenVPN:理论上限 1024 个并发客户端(受限于 `topology subnet` 子网大小,可改用 `net30` 提高) - 审计日志最多保留 5000 条 - 连接日志最多保留 20000 条 - 备份文件不自动清理,需定期手动删除过期备份