License 系统用于管理超级管理员级别的授权许可。
层级关系:平台 → 超级管理员 (License) → 租户 → 用户
基础 URL:http://<host>:<port>(开发环境默认 http://localhost:8000)
GET /api/license/super-admins
下拉选项接口,获取所有超级管理员,用于创建 License 时选择关联对象。
响应:
[
{
"id": 1,
"username": "admin1",
"nickname": "管理员A",
"remark": "客户A"
}
]
POST /api/license/
Content-Type: application/json
请求体:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
super_admin_id |
integer | 是 | 超级管理员 ID |
license_key |
string | 是 | License 密钥(1-200 字符) |
expires_at |
string | 是 | 过期时间(ISO 8601 格式) |
max_tenants |
integer | 否 | 可管理租户上限 |
max_users_per_tenant |
integer | 否 | 每租户用户上限 |
remark |
string | 否 | 备注 |
示例:
curl -X POST "http://localhost:8000/api/license/" \
-H "Content-Type: application/json" \
-d '{
"super_admin_id": 1,
"license_key": "LICENSE-2026-ABCDEF",
"expires_at": "2027-12-31T23:59:59",
"max_tenants": 10,
"remark": "年度授权"
}'
响应:
{
"message": "License已创建",
"license_id": 1
}
同一
super_admin_id只允许一个active状态的 License。重复创建会更新已有记录。
GET /api/license/list?super_admin_id=1&status=active&page=1&size=20
查询参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
super_admin_id |
integer | 否 | 按超管筛选 |
status |
string | 否 | active / expired / revoked |
page |
integer | 否 | 页码,默认 1 |
size |
integer | 否 | 每页条数,默认 20,最大 100 |
响应:
{
"total": 1,
"items": [
{
"id": 1,
"super_admin_id": 1,
"super_admin_name": "客户A",
"license_key": "LICENSE-2026-ABCDEF",
"expires_at": "2027-12-31T23:59:59",
"status": "active",
"max_tenants": 10,
"max_users_per_tenant": null,
"remark": "年度授权",
"created_at": "2026-05-13T10:00:00",
"updated_at": null
}
]
}
GET /api/license/{license_id}
响应:
{
"id": 1,
"super_admin_id": 1,
"super_admin_name": "客户A",
"license_key": "LICENSE-2026-ABCDEF",
"expires_at": "2027-12-31T23:59:59",
"status": "active",
"days_left": 232,
"max_tenants": 10,
"max_users_per_tenant": null,
"remark": "年度授权"
}
查询时如果
days_left <= 0,会自动将 License 状态更新为expired。
POST /api/license/{license_id}/revoke
响应:
{
"message": "License已吊销"
}
DELETE /api/license/{license_id}
响应:
{
"message": "License已删除"
}
提供给第三方系统调用的公开接口,无需认证。通过请求的 Referer 头自动匹配对应的监控域名,并返回该域名关联超管的 License 状态。
请求携带 Referer: https://example.com/page
→ 提取域名 example.com
→ 在 monitored_domains 表中匹配 domain = 'example.com'(需 is_active=true)
→ 获取该记录关联的 super_admin_id
→ 查询该超管当前 active 的 License
→ 返回 License 状态
GET /api/public/license/check
请求头:
| 头 | 类型 | 必填 | 说明 |
|---|---|---|---|
Referer |
string | 是 | 请求来源页面的完整 URL,用于提取域名匹配 |
curl 示例:
curl -H "Referer: https://example.com/dashboard" \
"http://localhost:8000/api/public/license/check"
{
"valid": true,
"status": "active",
"super_admin_name": "客户A",
"license_key": "LICENSE-2026-ABCDEF",
"expires_at": "2027-12-31T23:59:59",
"days_left": 232,
"max_tenants": 10,
"max_users_per_tenant": null,
"remark": "年度授权"
}
{
"valid": false,
"status": "unknown",
"message": "域名未注册或无关联超管"
}
{
"valid": false,
"status": "not_found",
"message": "未找到有效 License"
}
{
"valid": false,
"status": "unknown",
"message": "缺少 Referer 头"
}
| 字段 | 类型 | 出现条件 | 说明 |
|---|---|---|---|
valid |
boolean | 总是 | License 是否有效 |
status |
string | 总是 | active(有效)、not_found(未找到)、unknown(未知/错误) |
super_admin_name |
string | valid=true |
超管显示名称(优先取 remark,否则取 username) |
license_key |
string | valid=true |
License 密钥 |
expires_at |
string | valid=true |
过期时间(ISO 8601) |
days_left |
integer | valid=true |
剩余天数,负数表示已过期 |
max_tenants |
integer | valid=true |
可管理租户上限 |
max_users_per_tenant |
integer | valid=true |
每租户用户上限 |
remark |
string | valid=true |
License 备注 |
message |
string | valid=false |
失败原因说明 |
前端(浏览器自动携带 Referer):
const res = await fetch('/api/public/license/check');
const data = await res.json();
if (data.valid) {
console.log(`License 有效,剩余 ${data.days_left} 天`);
} else {
console.warn(`License 校验失败:${data.message}`);
}
Python 后端:
import requests
resp = requests.get(
"https://license-server.example.com/api/public/license/check",
headers={"Referer": "https://example.com/dashboard"},
)
print(resp.json())
Node.js:
const resp = await fetch("https://license-server.example.com/api/public/license/check", {
headers: { "Referer": "https://example.com/dashboard" },
});
console.log(await resp.json());
curl:
curl -H "Referer: https://example.com/dashboard" \
"https://license-server.example.com/api/public/license/check"
| 字段 | 类型 | 说明 |
|---|---|---|
id |
INTEGER PK | 主键 |
super_admin_id |
INTEGER | 关联的超管 ID |
license_key |
VARCHAR(200) | License 密钥 |
expires_at |
TIMESTAMPTZ | 过期时间 |
status |
VARCHAR(20) | active / expired / revoked |
max_tenants |
INTEGER | 租户上限 |
max_users_per_tenant |
INTEGER | 每租户用户上限 |
remark |
TEXT | 备注 |
created_at |
TIMESTAMPTZ | 创建时间 |
updated_at |
TIMESTAMPTZ | 更新时间 |
索引:super_admin_id, status, expires_at
| 字段 | 类型 | 说明 |
|---|---|---|
id |
INTEGER PK | 主键 |
domain |
VARCHAR (UNIQUE) | 域名 |
super_admin_id |
INTEGER | 关联的超管 ID |
is_active |
BOOLEAN | 是否启用 |
Q: 同一超管可以创建多个 License 吗?
A: 同一 super_admin_id 只允许一个 active 状态的 License。重复创建会更新已有记录。
Q: License 过期后会自动变为 expired 吗?
A: 会。每次查询 License 详情时会自动检查 days_left,如果 <= 0 则自动更新状态为 expired。
Q: 公开校验接口需要认证吗?
A: 不需要。GET /api/public/license/check 是公开接口,第三方系统可直接调用。
Q: 公开接口如果域名没有关联超管怎么办?
A: 返回 "valid": false, "status": "unknown", "message": "域名未注册或无关联超管"。