19 KiB
其他项目接入许可证验证系统说明
本文档面向“其他项目负责人”。
目标只有一个:让你的项目按统一方式接入当前 license-server 多项目验证系统,而不是各项目再各自实现一套授权服务。
这是一份给外部项目用的接入说明,不是 FLNXI 主项目的日常运维入口。FLNXI 主项目的真相和入口请优先看 README.md、docs/README.md 和 docs/deployment/部署说明.md。
说明:
- 当前仓库自己的主项目,确实主要面向 Docker / NAS / Linux 私有化部署
- 但“其他项目接入许可证系统”这件事,本身不要求项目一定跑在 Docker 里
- 只要项目侧有一个可信执行层可以承接许可证逻辑,就可以接入
- 对外沟通时可先发本文档作为接入主说明;涉及 FLNXI 主项目部署、当前生产配置或安全评估结论时,必须回到当前代码和对应部署文档复核,不能把本文当成全部事实来源
1. 先说结论
当前验证系统已经支持多项目接入,但新项目接入不是“零配置自动生效”,而是需要完成一次标准初始化。
接入时分成两部分:
- 验证系统侧负责:建项目、配项目库、开后台权限、准备联调环境
- 项目侧负责:按统一接口接入、配置项目编码、完成激活/验证/心跳/版本检查联调
只要你的项目能遵守本文档里的接口和配置约定,通常不需要再改 license-server 架构代码。
补充一条很重要:
- 项目侧运行环境不限定为 Docker。容器、Kubernetes、Linux 服务、Windows 服务、桌面程序配套本地服务,都可以接入
2. 谁负责什么
2.1 验证系统负责人负责
- 在
license-server主库中创建项目 - 为项目分配唯一
projectCode - 配置该项目对应的许可证数据库连接
- 初始化该项目库的许可证表结构
- 如有需要,为项目负责人创建后台账号并分配项目权限
- 提供联调地址、后台地址和项目编码
2.2 项目负责人负责
- 在自己项目中接入许可证验证流程
- 配置
LICENSE_SERVER_URL和LICENSE_PROJECT_CODE - 接通激活、验证、心跳接口
- 如项目有安装代理或版本升级能力,接通版本检查接口
- 完成自测并配合联调
3. 项目接入前要准备什么
项目负责人至少准备以下信息交给验证系统负责人:
- 项目名称
- 项目唯一编码
projectCode - 项目联系人
- 项目当前运行方式
- 例如:Docker / Kubernetes / Linux 服务 / Windows 服务 / 桌面程序本地服务 / 其它
- 项目是否有自己的后端或本地服务层
- 是否需要付费激活
- 是否需要免费试用
- 是否需要版本检查
- 是否需要 Agent 版本检查
- 该项目的许可证数据库连接信息
dbHostdbPortdbNamedbUserdbPassworddbSchema
- 需要接入后台管理的人员名单
projectCode 很关键,后续所有公开接口都会用到它,而且必须全链路一致。
建议格式:
小写英文 / 数字 / 连字符
示例:flnxi-sucai
4. 验证系统会给你什么
验证系统负责人完成初始化后,至少会给项目方这些信息:
LICENSE_SERVER_URL=https://license.example.com
LICENSE_PROJECT_CODE=your-project-code
LICENSE_REQUEST_SIGNING_SECRET=shared-secret-at-least-32-chars
如果项目需要后台管理,还会给:
- 后台地址:
/admin/login - 登录账号
- 项目是否已分配到该账号
4.1 联调地址和账号获取规则
本文档是对外接入说明,不记录内部服务器 IP、SSH 登录方式、后台账号或一次性联调密码。
正式联调时,由验证系统负责人通过独立渠道提供:
- 当前可用的
LICENSE_SERVER_URL - 当前项目的
LICENSE_PROJECT_CODE - 后台入口和后台账号(如需要)
- 测试许可证或测试发证方式
- 请求签名共享密钥
LICENSE_REQUEST_SIGNING_SECRET
不要把历史联调地址、个人账号或服务器登录方式写进项目代码、.env.example 或对外文档。
5. 统一接口规则
5.1 现在真正可用的公开接口
所有可用接口都必须带项目编码:
POST /api/license/{projectCode}/activate
POST /api/license/{projectCode}/verify
POST /api/license/{projectCode}/heartbeat
POST /api/license/{projectCode}/register-free
POST /api/license/{projectCode}/premium-modules
POST /api/license/{projectCode}/premium-modules/{moduleId}
POST /api/license/{projectCode}/premium-modules/{moduleId}/pull-token
POST /api/license/{projectCode}/generate
GET /api/registry/auth
GET /api/version/{projectCode}/check
GET /api/version/{projectCode}/agent
5.1.1 请求签名要求
activate、verify、heartbeat、register-free、premium-modules、premium-modules/{moduleId} 和 premium-modules/{moduleId}/pull-token 当前不是“只带项目编码就能访问”。项目侧可信执行层必须使用 LICENSE_REQUEST_SIGNING_SECRET 对请求体做 HMAC 签名,并把下面三个字段放进请求体:
{
"timestamp": 1779753600000,
"nonce": "32位随机十六进制字符串",
"signature": "sha256-hmac-hex"
}
签名计算口径以当前代码 lib/license/request-signature.ts 和 license-server/lib/request-signature.ts 为准:签名内容包含 action、projectCode 和按 key 排序后的请求体,且签名时会排除 signature 字段本身。远端会拒绝缺签名、签名错误、时间超出窗口和重复 nonce 的请求。
这和“验证许可证返回值的 RSA 签名”是两件事:请求签名用于防止外部伪造请求;许可证返回签名用于确认许可证内容没有被篡改。
如果项目需要拆分付费模块,还要额外接短期拉包凭证:验证系统先按 LicenseModuleGrant 判断该许可证是否允许使用某模块,再给 15 分钟有效的 pullToken。Registry 前置代理通过 GET /api/registry/auth 校验 token、仓库路径和 digest 后才放行拉取。发布账号只给发布方推镜像使用,不应发给客户现场。
5.2 禁止再使用的旧接口
以下旧接口已经废弃,当前统一返回 410:
/api/license/activate
/api/license/verify
/api/license/heartbeat
/api/license/register-free
/api/license/generate
/api/version/check
/api/version/agent
如果你的项目还在调用这些旧路径,说明还没有接完。
5.3 AI 落地时必须遵守的最少规则
如果项目负责人是用 AI 做接入,至少要让 AI 严格遵守这 6 条:
- 只能调用带
projectCode的新接口 - 不要继续使用任何旧的无项目接口
- 不要让前端直接连
license-server - 必须有一个可信执行层承接验证逻辑
- 必须做本地许可证缓存,并校验服务端返回许可证的签名
LICENSE_PROJECT_CODE必须与验证系统登记值完全一致
6. 推荐接入方式与运行环境要求
推荐模式:由你项目里的“可信执行层”做代理,不要让前端、纯脚本或纯静态页面直接调用远端 license-server。
原因:
- 可以隐藏真实验证服务器地址
- 可以在你自己的服务层生成硬件指纹
- 可以在你自己的服务层做签名验证和本地缓存
- 可以减少前端暴露敏感校验逻辑
这里的“可信执行层”不要求一定是 Docker 容器里的后端,它可以是:
- Web 项目的后端接口
- 桌面程序配套的本地服务或守护进程
- 安装代理、Launcher、常驻进程
- 业务服务自身的服务端模块
- Kubernetes / 容器里的应用服务
只要满足这 4 条,就具备接入基础:
- 能稳定读取
LICENSE_SERVER_URL和LICENSE_PROJECT_CODE - 能访问远端
license-server - 能处理硬件指纹、本地许可证缓存、签名校验
- 能避免把敏感逻辑全部暴露给前端或最终用户
推荐链路示例:
浏览器
-> 你的项目后端 /api/license/*
-> license-server /api/license/{projectCode}/*
桌面程序
-> 本地服务 / 守护进程
-> license-server /api/license/{projectCode}/*
业务服务
-> 自身服务端模块
-> license-server /api/license/{projectCode}/*
如果你的项目有安装 Agent,版本检查也建议走统一配置:
LICENSE_SERVER_URL + LICENSE_PROJECT_CODE
不推荐的方式:
- 纯前端页面直接请求
license-server - 把项目编码、签名校验和完整验证逻辑全部暴露到浏览器端
- 没有任何本地可信层,却想直接做安全授权
如果你的项目没有独立后端,也没有本地服务层,请先补一个最小代理层,再谈接入。
7. 项目侧至少要接通的能力
7.0 通用返回结构说明
涉及许可证返回时,核心结构按下面理解即可:
{
"data": {
"type": "FREE | STANDARD | PRO",
"limits": {
"maxUsers": 10,
"maxMaterials": 100
},
"features": {
"customTemplates": false,
"systemSettings": false,
"departmentIsolation": false,
"apiAccess": false,
"intranetPenetration": false
},
"expiresAt": null,
"issuedAt": "2026-03-13T00:00:00.000Z"
},
"signature": "base64-signature",
"issuedAt": "2026-03-13T00:00:00.000Z"
}
状态码通常按下面理解:
200:请求成功400:参数错误、请求过期、格式不合法403:许可证禁用、过期、指纹不匹配、无权限404:项目不存在、许可证不存在、激活记录不存在409:许可证已在其他设备激活410:还在调用旧接口500:服务端错误
7.1 激活
用于输入激活码后完成首次授权。
目标接口:
POST /api/license/{projectCode}/activate
最少请求字段:
{
"licenseKey": "XXXX-XXXX-XXXX-XXXX",
"fingerprint": {
"machineId": "xxx",
"hostname": "xxx",
"macAddress": "xxx",
"instanceId": "xxx"
},
"timestamp": 1700000000000
}
成功后会返回签名许可证,项目侧应自行保存本地许可证缓存。
成功响应可按下面理解:
{
"success": true,
"license": {
"data": {
"type": "STANDARD",
"limits": {
"maxUsers": -1,
"maxMaterials": -1
},
"features": {
"customTemplates": true,
"systemSettings": true,
"departmentIsolation": true,
"apiAccess": true,
"intranetPenetration": false
},
"expiresAt": null,
"issuedAt": "2026-03-13T00:00:00.000Z"
},
"signature": "base64-signature",
"issuedAt": "2026-03-13T00:00:00.000Z"
}
}
7.2 验证
用于已激活实例的定期校验。
目标接口:
POST /api/license/{projectCode}/verify
最少请求字段:
{
"instanceId": "xxx",
"fingerprint": {
"machineId": "xxx",
"hostname": "xxx",
"macAddress": "xxx",
"instanceId": "xxx"
},
"timestamp": 1700000000000
}
成功响应可按下面理解:
{
"valid": true,
"license": {
"data": {
"type": "STANDARD",
"limits": {
"maxUsers": -1,
"maxMaterials": -1
},
"features": {
"customTemplates": true,
"systemSettings": true,
"departmentIsolation": true,
"apiAccess": true,
"intranetPenetration": false
},
"expiresAt": null,
"issuedAt": "2026-03-13T00:00:00.000Z"
},
"signature": "base64-signature",
"issuedAt": "2026-03-13T00:00:00.000Z"
}
}
7.3 心跳
用于持续上报实例状态和使用量。
目标接口:
POST /api/license/{projectCode}/heartbeat
最少请求字段:
{
"instanceId": "xxx",
"fingerprint": {
"machineId": "xxx",
"hostname": "xxx",
"macAddress": "xxx",
"instanceId": "xxx"
},
"usage": {
"userCount": 10,
"materialCount": 100
},
"timestamp": 1700000000000
}
成功响应可按下面理解:
{
"acknowledged": true,
"license": {
"data": {
"type": "STANDARD",
"limits": {
"maxUsers": -1,
"maxMaterials": -1
},
"features": {
"customTemplates": true,
"systemSettings": true,
"departmentIsolation": true,
"apiAccess": true,
"intranetPenetration": false
},
"expiresAt": null,
"issuedAt": "2026-03-13T00:00:00.000Z"
},
"signature": "base64-signature",
"issuedAt": "2026-03-13T00:00:00.000Z"
}
}
7.4 免费试用
如果你的项目支持免费试用,再接:
POST /api/license/{projectCode}/register-free
最少请求字段:
{
"fingerprint": {
"machineId": "xxx",
"hostname": "xxx",
"macAddress": "xxx",
"instanceId": "xxx"
},
"customerName": "某某公司",
"contactInfo": "手机号/微信/邮箱",
"timestamp": 1700000000000
}
成功响应可按下面理解:
{
"success": true,
"data": {
"activationCode": "FLNXI-FREE-XXXX-XXXX-XXXX-XXXX",
"plan": "FREE",
"planName": "免费版",
"isExisting": false
}
}
7.5 版本检查
如果你的项目有升级提示或安装代理,需要接:
GET /api/version/{projectCode}/check
GET /api/version/{projectCode}/agent
版本检查响应可按下面理解:
{
"latestVersion": "1.0.0",
"minRequiredVersion": "1.0.0",
"releaseNotes": "更新说明",
"releaseDate": "2026-03-13T00:00:00.000Z",
"isSecurityUpdate": false,
"isCriticalUpdate": false,
"downloadSize": "120MB"
}
Agent 版本检查响应可按下面理解:
{
"latestVersion": "1.0.0",
"releaseNotes": "更新说明",
"releaseDate": "2026-03-13T00:00:00.000Z"
}
7.6 付费激活码生成
如果你的项目需要由系统接口生成付费激活码,再接:
POST /api/license/{projectCode}/generate
该接口不是普通前端直调接口。当前真实要求:
- Header 必须带
X-API-Key - 请求体必须带
timestamp - 请求体必须带
sign sign当前按md5(orderNo + timestamp + apiKey)校验- 请求时间窗口为 5 分钟
最少请求字段:
{
"orderNo": "ORDER-20260513-001",
"plan": "STANDARD",
"customerEmail": "customer@example.com",
"customerName": "某某公司",
"contactInfo": "联系人电话/微信/邮箱",
"validDays": 365,
"timestamp": 1778660000000,
"sign": "md5-sign"
}
当前 plan 仅支持 STANDARD 和 PRO。FREE 走免费试用注册链路,不走发证接口。
8. 项目配置要求
项目侧至少要能提供这三个配置项:
LICENSE_SERVER_URL=https://license.example.com
LICENSE_PROJECT_CODE=your-project-code
LICENSE_REQUEST_SIGNING_SECRET=shared-secret-at-least-32-chars
这三个值不一定非要写在 .env 里,也可以放在:
- 系统环境变量
- 项目配置文件
- 服务启动参数
- Kubernetes Secret / ConfigMap
- Windows 服务配置
- 桌面程序本地安全配置
核心不是“必须用环境变量”,而是“运行时必须能稳定、安全地读到这些值”。
要求:
LICENSE_PROJECT_CODE必须和验证系统中登记的项目编码完全一致LICENSE_REQUEST_SIGNING_SECRET必须和许可证服务中同项目使用的共享密钥一致,至少 32 字符,不能放到浏览器端- 不要在多个地方写不同的项目编码
- 不要继续写死旧的无项目接口地址
9. 后台管理规则
接入完成后,后台将按项目维度工作。
常见路径:
/admin/select-project
/admin/{projectCode}
/admin/{projectCode}/licenses
/admin/{projectCode}/alerts
/admin/{projectCode}/versions
/admin/{projectCode}/customers
/admin/{projectCode}/api-keys
规则:
- 普通管理员只能看到被分配的项目
- 超级管理员可以管理所有项目
- 是否给项目负责人开放后台,由验证系统负责人决定
10. 标准接入流程
建议严格按下面顺序推进:
- 项目方提交接入申请
- 验证系统负责人创建项目并初始化项目库
- 验证系统负责人返回
LICENSE_SERVER_URL和LICENSE_PROJECT_CODE - 项目方确认由谁承接许可证逻辑
- 后端
- 本地服务
- 安装代理
- 其它可信执行层
- 项目方在自己的可信执行层接入激活、验证、心跳接口
- 如有需要,项目方接入免费试用和版本检查
- 项目方完成本地自测
- 双方做联调
- 联调通过后再进入正式环境
11. 联调验收清单
上线前至少确认这些项:
- 能用正确的
projectCode激活 - 激活成功后能拿到许可证并本地保存
- 验证接口能返回有效结果
- 心跳接口能正常返回
- 许可证禁用后,项目侧能识别失效状态
- 旧的无项目接口已经不再被调用
- 如启用免费试用,免费注册链路可用
- 如启用版本检查,版本接口能返回数据
- 后台能进入对应项目,而不是进入错误项目
12. 常见错误
12.1 项目编码不一致
最常见问题。
现象:
- 返回
404 项目不存在 - 或者进入了错误项目的数据
处理:
- 检查项目方实际运行配置里的
LICENSE_PROJECT_CODE - 检查验证系统主库中登记的
projects.code
12.2 还在调用旧接口
现象:
- 返回
410
处理:
- 全量搜索项目代码里的旧路径
- 改成
/api/license/{projectCode}/... - 改成
/api/version/{projectCode}/...
12.3 前端直连验证服务器
现象:
- 暴露远端地址
- 暴露部分校验逻辑
- 后续切环境不方便
处理:
- 改成项目里的可信执行层代理,不一定非要是 Web 后端
12.4 没有做本地缓存和签名校验
现象:
- 每次使用都强依赖网络
- 许可证返回后没有校验服务端签名
处理:
- 在项目的可信执行层保存许可证缓存
- 对返回许可证做签名验证;这和
activate / verify / heartbeat请求本身是否带签名不是一回事 - 再决定是否放行业务功能
13. 什么时候需要改验证系统代码
一般不需要。
只有在以下情况,才可能需要验证系统侧继续开发:
- 你的项目许可证模型与现有模型明显不同
- 你的项目需要新的授权等级或功能开关
- 你的项目需要新的使用量统计字段
- 你的项目需要不同的激活/验证规则
- 你的项目需要新的后台管理能力
如果只是普通的“接一个新项目”,通常不需要改 license-server 业务代码。
14. 接入时建议直接同步确认的事项
为了减少来回沟通,建议项目负责人一次性确认这 10 项:
- 项目编码叫什么
- 项目实际运行环境是什么
- 由谁承接许可证逻辑
- 是否要独立许可证库
- 是否要免费试用
- 是否要版本检查
- 是否要 Agent 版本检查
- 谁有后台权限
- 测试环境地址和正式环境地址分别是什么
- 验收标准是什么
15. 补充说明
如果你是“项目负责人”而不是“验证系统管理员”,你不需要自己去改 license-server 服务器内部配置。
你真正需要做的是:
- 把项目接入参数拿到手
- 按统一接口把自己项目接上去
- 把联调和验收跑通
对外接入可先看本文件;涉及部署、线上地址、安全结论或 FLNXI 主项目差异时,必须同步引用当前代码和对应部署说明,不能只发旧快照或内部台账。
下面这些文档属于当前项目内部补充资料,不是对方接入时的必读项:
docs/许可证服务接入说明.md
历史安全评估快照和内部整改台账不建议对外发送;如果必须引用,需要先按当前代码、部署文件和实际环境重新复核。