公告管理
纯文本公告。换行用 </br>,颜色标签:<red>红字</red>、<blue>蓝字</blue>。公开接口 GET /api/announcement 原样输出。
实时预览
卡密生成
卡密时长
卡密管理
| 卡密 | 时长 | 创建时间 | 到期时间 | 状态 | 操作 |
|---|
注册码管理(设备指纹注册)
POST /api/pc/register 上报电脑信息生成 base64 码与密钥;同一设备指纹只生成一次。
| 设备 / 指纹 | Base64 码 | 密钥 | 到期时间 | 状态 | 操作 |
|---|
📖 开发文档
所有接口返回 JSON(公告纯文本接口除外)。管理员接口必须携带有效未过期的 aluo_session Cookie(登录后自动写入,2 小时有效),否则返回 401。登录接口 POST /api/login 公开、不限次数。
状态码说明
| 状态码 | 含义 |
|---|---|
| 200 | 成功 |
| 201 | 创建成功 |
| 400 | 参数错误(缺参数 / 格式不对) |
| 401 | 未登录 / 会话过期 / 卡密不存在 |
| 403 | 已到期 / 无权访问 |
| 404 | 接口不存在 / 记录不存在 |
| 409 | 卡密已存在(冲突) |
| 500 | 服务器内部错误 |
一、公共接口(无需登录)
POST/api/login — 管理员登录,下发 Cookie
// 200 成功(自动 Set-Cookie: aluo_session=...; Max-Age=7200)
{"result":"OK","login":true,"status":200,"message":"登录成功","user":"aluo1207","expiresAt":"2026-10-19 13:33:00","cookieMaxAge":7200}
// 401 失败
{"result":"FALSE","login":false,"status":401,"message":"用户名或密码错误"}
GET/api/announcement — 读取公告(纯文本原样输出)
GET/api/kami?kami=卡密 — 模拟登录,校验卡密有效性 和 时长
// 200 有效
{"result":"OK","login":true,"status":200,"kami":"Ab3dEf9Gh2JkLmN","expiresAt":"2026-10-20 11:33:00","duration":"天卡","message":"卡密有效,登录成功"}
// 401 卡密不存在 / 403 已到期
{"result":"FALSE","login":false,"status":403,"kami":"Ab3dEf9Gh2JkLmN","expiresAt":"2026-10-19 10:00:00","message":"卡密已到期"}
GET/api/kami2?kami2=卡密 — 只验证卡密是否存在,不验证时长
// 200 存在
{"result":"OK","login":true,"status":200,"kami2":"Ab3dEf9Gh2JkLmN","message":"卡密存在(未校验时长)"}
// 401 不存在
{"result":"FALSE","login":false,"status":401,"kami2":"xxx","message":"卡密不存在"}
GET/api/pckami?pckami=密钥 — 校验 PC 注册码有效性和时长
// 200 有效
{"result":"OK","login":true,"type":"PC","status":200,"pckami":"xY9kQ2mP7rT4wZ","expiresAt":"2026-10-19 12:33:00","duration":"一小时卡","message":"注册码有效,登录成功"}
// 401 不存在 / 403 已到期
{"result":"FALSE","login":false,"type":"PC","status":403,"pckami":"xY9kQ2mP7rT4wZ","expiresAt":"2026-10-19 11:00:00","message":"注册码已到期"}
POST/api/pc/register — 设备注册(上报电脑信息,同指纹只生成一次)
// 201 首次注册(自动生成一小时卡密钥)
{"result":"OK","status":201,"message":"注册成功,已自动生成密钥","id":"...","fp":"a1b2c3...","base64":"eyJmcCI6...","pckami":"xY9kQ2mP7rT4wZ","expiresAt":"2026-10-19 12:33:00"}
// 200 相同设备指纹再次请求 → 返回原记录,不重新生成
{"result":"EXIST","status":200,"message":"相同设备指纹已注册,返回原密钥(环境变更才会重新生成)","id":"...","fp":"...","base64":"...","pckami":"xY9kQ2mP7rT4wZ","expiresAt":"...","status2":"有效"}
二、管理员接口(必须携带有效未过期 Cookie)
Cookie: aluo_session=...(HttpOnly,2 小时)。2 小时后必须重新调用 /api/login 获取新 Cookie。curl 示例:curl -b cookie.txt -c cookie.txt ...
POST/api/logout — 退出并清除 Cookie
GET/api/session — 校验会话
{"result":"OK","login":true,"status":200,"user":"aluo1207","expiresAt":"2026-10-19 13:33:00"}
// 未登录:401 {"result":"FALSE",...,"message":"未登录或会话已过期..."}
GET/api/stats — 统计概览
{"result":"OK","status":200,"keys":{"total":20,"valid":15,"expired":5},"pcs":{"total":3,"valid":2}}
PUT/api/announcement — 保存公告
{"result":"OK","status":200,"announcement":"...","message":"公告已保存"}
POST/api/keys/generate — 生成卡密(随机或自定义)
// duration 三种写法:
{"mode":"preset","value":"1h"} // 预设:1h 一小时 / 1d 天 / 1w 周 / 1m 月 / 1y 年 / forever 永久
{"mode":"hours","hours":12.5} // 按小时(支持小数)
{"mode":"datetime","datetime":"2026-12-31 23:59:59"} // 按日历,精确到秒
// 201 成功
{"result":"OK","status":201,"key":"Ab3dEf9Gh2JkLmN","duration":"天卡","expiresAt":"2026-10-20 11:33:00","message":"卡密创建成功"}
// 409 自定义卡密已存在
GET/api/keys — 卡密列表(表格数据源)
{"result":"OK","status":200,"total":20,"keys":[
{"key":"Ab3dEf9Gh2JkLmN","desc":"天卡","createdAt":"2026-10-19 11:33:00","expiresAt":"2026-10-20 11:33:00","status":"有效","valid":true},
{"key":"Zz8yXx7v...","desc":"一小时卡","createdAt":"2026-10-19 09:00:00","expiresAt":"2026-10-19 10:00:00","status":"已到期","valid":false}
]}
POST/api/keys/delete — 删除卡密(支持单删 / 批量)
{"result":"OK","status":200,"deleted":2,"message":"已删除 2 条卡密"}
GET/api/pc/list — 注册设备列表(指纹 / 电脑信息 / base64 / 密钥)
POST/api/pc/key — 重新生成设备密钥(旧密钥立即失效)
{"result":"OK","status":200,"id":"...","pckami":"NewRandomKey9Qx","duration":"月卡","expiresAt":"2026-11-19 11:33:00","message":"密钥已重新生成"}
POST/api/pc/delete — 删除设备记录 {"ids":[...]} 或 {"id":"..."}
三、客户端设备指纹采集参考(JS)
const info = {
ua: navigator.userAgent,
screen: screen.width + "x" + screen.height + "@" + screen.colorDepth,
lang: navigator.language,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
platform: navigator.platform,
cores: navigator.hardwareConcurrency,
memory: navigator.deviceMemory
};
fetch("/api/pc/register", {method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify(info)})
.then(r=>r.json()).then(d=>console.log(d.pckami));