diff --git a/frontend/src/views/Integration.vue b/frontend/src/views/Integration.vue index 1288fb9..b62bbdf 100644 --- a/frontend/src/views/Integration.vue +++ b/frontend/src/views/Integration.vue @@ -13,7 +13,27 @@ title="接入三步:① 拿到产品序列号(后台或购买页) ② 客户端调 activate 激活并保存 activation_token ③ 每周调 verify 周检(验签 sig + 时钟校验)" />

接入模型

-
{{ flowText }}
+
+
+
+ 客户端 + 桌面 / CLI / Web 前端 +
+
+ ① activate(序列号,设备ID)⟶ + ⟵ activation_token + sig +
+
+ 授权服务器(双节点) + licence.rlwj.cn + l123.91ai.io +
+
+
+
+ {{ st.title }}{{ st.detail }} +
+
+

客户端 API(无需认证,按 IP 限流)

@@ -23,6 +43,18 @@ +

请求体参数

+ + + + + +

快速自测

+
+ {{ copied === 'curl' ? '已复制' : '复制' }} +
+
+

验证/激活响应关键字段

@@ -120,8 +152,10 @@ import hljsJava from 'highlight.js/lib/languages/java' import hljsPython from 'highlight.js/lib/languages/python' import hljsXml from 'highlight.js/lib/languages/xml' import hljsJavascript from 'highlight.js/lib/languages/javascript' +import hljsBash from 'highlight.js/lib/languages/bash' import 'highlight.js/styles/github-dark.css' -import { clientSnippets, cliSnippets, backendSnippets, API_ENDPOINTS, CANONICAL_SPEC } from './integration/snippets/index.js' +import { clientSnippets, cliSnippets, backendSnippets, CANONICAL_SPEC } from './integration/snippets/index.js' +import { apis as API_ROWS, params as PARAM_ROWS, fields as FIELD_ROWS, flowSteps as FLOW_STEPS, CURL_EXAMPLE, API_ENDPOINTS as EP } from './integration/docData.js' import request from '@/api/request' hljs.registerLanguage('go', hljsGo) @@ -130,6 +164,13 @@ hljs.registerLanguage('java', hljsJava) hljs.registerLanguage('python', hljsPython) hljs.registerLanguage('xml', hljsXml) hljs.registerLanguage('javascript', hljsJavascript) +hljs.registerLanguage('bash', hljsBash) + +const apis = API_ROWS +const params = PARAM_ROWS +const fields = FIELD_ROWS +const flowSteps = FLOW_STEPS +const API_ENDPOINTS = EP const tab = ref('overview') const cliKind = ref('go') @@ -166,38 +207,7 @@ const copy = async (text, key) => { setTimeout(() => { copied.value = '' }, 1200) } -const flowText = `┌──────────┐ ① activate(序列号, 设备ID) ┌──────────────────┐ -│ 客户端 │ ────────────────────────────▶ │ 授权服务器(双节点) │ -│ 桌面/CLI │ ◀──────────────────────────── │ 国内 + 香港容灾 │ -│ Web前端 │ activation_token + sig └──────────────────┘ -└────┬─────┘ - │ ② 每周 verify / heartbeat(多端点按序尝试,超时8s切换) - │ 验签 sig → 通过则按 valid / in_grace 放行 - │ ③ 本机解绑 deactivate(须携带 activation_token) - ▼ - 离线证 LICOFF-:Ed25519 自包含验证,绑设备ID,最长365天,不依赖网络` -const apis = [ - { method: 'POST', path: '/api/v1/license/verify', who: '客户端', desc: '周检验证:返回 valid / in_grace / sig / server_time' }, - { method: 'POST', path: '/api/v1/license/activate', who: '客户端', desc: '激活占座:新设备下发一次性 activation_token' }, - { method: 'POST', path: '/api/v1/license/deactivate', who: '客户端', desc: '解绑本机:必须携带 activation_token' }, - { method: 'POST', path: '/api/v1/license/heartbeat', who: '客户端', desc: '活跃上报:刷新 last_seen(后台"在线"依据)' }, - { method: 'POST', path: '/api/v1/license/devices', who: '客户端', desc: '本序列号的已绑定设备列表' }, - { method: 'GET', path: '/api/v1/products/code/:code', who: '购买页', desc: '产品信息与定价(展示用)' }, - { method: 'POST', path: '/api/v1/orders · /checkout · /purchase/claim', who: '购买页', desc: '下单 / 支付 / 支付完成领取序列号' }, -] - -const fields = [ - { name: 'valid', desc: '是否有效。宽限期内为 true(配合 in_grace 判断提示续费)' }, - { name: 'status', desc: 'active / inactive / expired / revoked / suspended;吊销与暂停无宽限' }, - { name: 'expires_at / expires_at_unix', desc: '到期时间(字符串展示用;unix 为签名字段,直接回用免时区换算)' }, - { name: 'days_left / grace_days_left', desc: '剩余天数 / 宽限剩余天数' }, - { name: 'max_devices / plan_type', desc: '最大设备数 / 套餐类型(trial | monthly | yearly | perpetual)' }, - { name: 'in_grace', desc: '宽限期标记:商业过期 15 天内为 true,照常放行' }, - { name: 'server_time', desc: '服务端时间(unix 秒):客户端本地时钟不得早于历史最大值(防回拨)' }, - { name: 'sig', desc: 'Ed25519 签名(hex):验签失败按未授权处理(假服务器/篡改)' }, - { name: 'activation_token', desc: '仅 activate 响应:一次性下发的设备令牌,解绑必须携带,须持久保存' }, -] diff --git a/frontend/src/views/integration/docData.js b/frontend/src/views/integration/docData.js new file mode 100644 index 0000000..95b456b --- /dev/null +++ b/frontend/src/views/integration/docData.js @@ -0,0 +1,47 @@ +/** + * @file docData.js + * @description 接入文档页的结构化数据:API 契约表、字段表、参数表、时序步骤。 // Logan.Li + */ + +export const API_ENDPOINTS = ['https://licence.rlwj.cn', 'https://l123.91ai.io'] + +export const apis = [ + { method: 'POST', path: '/api/v1/license/verify', who: '客户端', desc: '周检验证:返回 valid / in_grace / sig / server_time(裸对象)' }, + { method: 'POST', path: '/api/v1/license/activate', who: '客户端', desc: '激活占座:新设备下发一次性 activation_token(信封,签名在 data)' }, + { method: 'POST', path: '/api/v1/license/deactivate', who: '客户端', desc: '解绑本机:必须携带 activation_token' }, + { method: 'POST', path: '/api/v1/license/heartbeat', who: '客户端', desc: '活跃上报:刷新 last_seen(后台"在线"依据,信封同 activate)' }, + { method: 'POST', path: '/api/v1/license/devices', who: '客户端', desc: '本序列号的已绑定设备列表' }, + { method: 'GET', path: '/api/v1/products/code/:code', who: '购买页', desc: '产品信息与定价(展示用)' }, + { method: 'POST', path: '/api/v1/checkout · /orders · /purchase/claim', who: '购买页', desc: '下单 / 支付 / 支付完成领取序列号' }, +] + +export const params = [ + { api: 'verify', body: '{ "license_key": "LIC-…", "device_id": "设备唯一ID" }' }, + { api: 'activate', body: '{ "license_key": "LIC-…", "device_id": "设备唯一ID", "device_name": "可选展示名" }' }, + { api: 'deactivate', body: '{ "license_key": "LIC-…", "device_id": "设备唯一ID", "activation_token": "激活时下发" }' }, + { api: 'heartbeat', body: '{ "license_key": "LIC-…", "device_id": "设备唯一ID" }' }, +] + +export const fields = [ + { name: 'valid', desc: '是否有效。宽限期内为 true(配合 in_grace 判断提示续费)' }, + { name: 'status', desc: 'active / inactive / expired / revoked / suspended;吊销与暂停无宽限' }, + { name: 'expires_at / expires_at_unix', desc: '到期时间(字符串展示用;unix 为签名字段,直接回用免时区换算)' }, + { name: 'days_left / grace_days_left', desc: '剩余天数 / 宽限剩余天数' }, + { name: 'max_devices / plan_type', desc: '最大设备数 / 套餐类型(trial | monthly | yearly | perpetual)' }, + { name: 'in_grace', desc: '宽限期标记:商业过期 15 天内为 true,照常放行' }, + { name: 'server_time', desc: '服务端时间(unix 秒):客户端本地时钟不得早于历史最大值(防回拨)' }, + { name: 'sig', desc: 'Ed25519 签名(hex):验签失败按未授权处理(假服务器/篡改)' }, + { name: 'activation_token', desc: '仅 activate 响应:一次性下发的设备令牌,解绑必须携带,须持久保存' }, +] + +export const flowSteps = [ + { title: '① 激活', detail: 'activate(序列号, 设备ID) → 服务端占座并下发一次性 activation_token + 签名 sig,客户端持久保存两者' }, + { title: '② 周检', detail: '每周 verify / heartbeat(多端点按序尝试,超时 8s 切换)→ 验签 sig → 按 valid / in_grace 放行,宽限期提示续费' }, + { title: '③ 解绑', detail: '本机解绑 deactivate 必须携带 activation_token;仅凭序列号无法解绑他人设备' }, + { title: '离线证', detail: 'LICOFF- 前缀为 Ed25519 自包含验证:绑设备 ID、最长 365 天、不依赖网络,服务端仅留审计' }, +] + +export const CURL_EXAMPLE = `# 快速验证(替换为真实序列号) +curl -sS -X POST https://licence.rlwj.cn/api/v1/license/verify \\ + -H 'Content-Type: application/json' \\ + -d '{"license_key":"LIC-XXXX-XXXX-XXXX-XXXX","device_id":"demo"}'`