Files
craftlabs-authorization-sdk/docs/superpowers/specs/2026-05-18-selfhosted-licensing-sdk-design.md
T

20 KiB
Raw Blame History

自研授权 SDK 设计方案

日期2026-05-18 背景:比特安索授权云费用过高,决定优先推进自研授权方案。 原则:与比特安索双线共存,Provider 可扩展架构,后续可接入更多第三方授权方式。


目录

  1. 决策摘要
  2. 总体架构
  3. 许可证协议与数据模型
  4. Rust 层核心逻辑
  5. 平台后端变更
  6. 安全设计
  7. 实施阶段

1. 决策摘要

决策项 选择 理由
授权服务形态 混合模式 有网络时在线验证(心跳/租约续期),断网时本地缓存可用至离线宽限期
加密体系 非对称签名 RSA-256 + AES-256-GCM 加密载荷 离线验签 + 内容加密防窥探,每个 license 独立 AES 密钥防批量破解
授权粒度 完整属性:有效期 + 终端限制 + 并发用户数 + 使用次数 + 特性开关 对齐现有比特业务属性,功能上不降级
后端集成 复用 API + Webhook 双服务 签发走 API(管理操作需认证鉴权),SDK 交互走 Webhook(高频快速 2xx
比特兼容 双线共存 + Provider 可扩展架构 后续可接入更多第三方
终端识别 硬件指纹分层采集 + 稳定度评分兜底 强指纹精确匹配,弱指纹分配服务器 UUID,管理员可手动释放
Rust 架构 单 cdylib + trait 多 Provider 公共模块共享,扩展第三方只需增加 trait 实现
SDK 交互安全 Nonce + Timestamp + HMAC 签名防重放 简单有效,无需序列号同步

2. 总体架构

2.1 全系统组件图

┌─────────────────────────────────────────────────────────────────┐
│                         客户现场                                 │
│  ┌──────────┐    ┌──────────────────┐    ┌──────────────────┐   │
│  │ 客户应用   │───▶│ Java SDK         │    │ 许可证配置文件     │   │
│  └──────────┘    │ AuthProvider impl │◀───│ ~/.craftlabs/     │   │
│                  │ ┌──────────────┐ │    │   license_cache   │   │
│                  │ │BitAnswerProv │ │    │   device_id       │   │
│                  │ ├──────────────┤ │    └──────────────────┘   │
│                  │ │SelfHostedPrv │ │                            │
│                  │ └──────┬───────┘ │                            │
│                  └────────┼────────┘                            │
│                           │ JNI                                 │
│                  ┌────────▼────────┐                            │
│                  │ Rust craft-core │  libcraftlabs_auth_core    │
│                  │ ◇ trait Provider│                            │
│                  │ ┌─────────────┐ │                            │
│                  │ │BitAnswer    │ │──────▶ 比特安索云           │
│                  │ ├─────────────┤ │                            │
│                  │ │SelfHosted   │ │──HTTPS▶ license-webhook    │
│                  │ └─────────────┘ │                            │
│                  │ device.rs      │ 硬件指纹分层采集              │
│                  │ crypto.rs      │ HKDF+AES-GCM+RSA验签        │
│                  │ security/      │ 反调试/完整性/混淆            │
│                  └────────────────┘                            │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│                       创飞机房 / 云                              │
│                                                                 │
│  ┌──────────────────────────┐   ┌──────────────────────────┐    │
│  │ license-webhook-ingress  │   │ delivery-platform-api    │    │
│  │ :8081                    │   │ :8080                    │    │
│  │ SDK 在线端点:             │   │ 许可证签发端点:            │    │
│  │ /license/v1/activate     │◀──│ /api/v1/licenses         │    │
│  │ /license/v1/heartbeat    │   │ /api/v1/licenses/{id}    │    │
│  │ /license/v1/check        │   │ /api/v1/licenses/{id}/   │    │
│  │ /license/v1/release      │   │   revoke                 │    │
│  │                          │   │                          │    │
│  │ 事件回调 ─────────────▶  │   │ 合同/SN/终端/审计         │    │
│  └──────────────────────────┘   └──────────────────────────┘    │
│              │                            │                      │
│              └──────────┬─────────────────┘                      │
│                         ▼                                       │
│                  ┌──────────────┐                                │
│                  │ PostgreSQL 15│                                │
│                  └──────────────┘                                │
└─────────────────────────────────────────────────────────────────┘

2.2 Rust 层模块结构(改造后)

native/craft-core/src/
├── lib.rs                     # cdylib 入口 + C ABI 路由
├── trait_provider.rs           # Provider trait 定义 + select_provider
│
├── provider_bitanswer/         # 现有逻辑封装
│   ├── mod.rs
│   ├── activate.rs
│   ├── license.rs
│   └── heartbeat.rs
│
├── provider_selfhosted/        # ★ 本次核心交付
│   ├── mod.rs                  # SelfHostedProvider impl Provider
│   ├── activate.rs             # HTTPS POST → webhook:8081
│   ├── license.rs              # 验签 + 解密 + 离线校验
│   ├── heartbeat.rs            # HTTPS 心跳 + 租约续期
│   ├── protocol.rs             # 请求/响应序列化
│   └── cache.rs                # 许可证本地加密存储
│
├── device.rs                   # ★ 硬件指纹分层采集
├── crypto.rs                   # ★ HKDF + AES-256-GCM + RSA 验签
├── session.rs                  # 泛化 session(去 bit_handle
├── error.rs                    # 自研 + 比特错误码体系
│
└── security/                   # 不变
    ├── mod.rs
    ├── anti_debug.rs
    ├── integrity.rs
    ├── obfuscation.rs
    └── string_encrypt.rs

2.3 Provider trait 契约

pub trait Provider: Send + Sync {
    fn initialize(&mut self, ctx: &CraftContext, config: &AuthConfig) 
        -> Result<(), LicenseError>;
    fn activate(&self, ctx: &CraftContext, license_key: &str) 
        -> Result<ActivateResponse, LicenseError>;
    fn check_license(&self, ctx: &CraftContext) 
        -> Result<LicenseStatus, LicenseError>;
    fn heartbeat(&self, ctx: &CraftContext) 
        -> Result<HeartbeatResponse, LicenseError>;
    fn has_feature(&self, ctx: &CraftContext, name: &str) -> bool;
    fn release(&mut self, ctx: &CraftContext) -> Result<(), LicenseError>;
    fn get_license_info(&self, ctx: &CraftContext) -> LicenseInfoFFI;
    fn close(&mut self);
}

2.4 Java 层变更

模块 变更
craftlabs-auth-core 接口不变;SelfhostedConfigSection 扩展 offlineGraceDaysheartbeatIntervalHours 等字段;FeatureMapping 扩展 selfhostedFeatureKey
craftlabs-auth-bitanswer 不变(双线共存)
craftlabs-auth-selfhosted 从桩改为真实实现:System.loadLibrary("craftlabs_auth_core")
craftlabs-auth-tests 新增 SelfHostedProviderTestMultiProviderSmokeTest

2.5 关键架构约束

  • 单一 cdylibcraftlabs_auth_core 包含所有 provider,通过 trait 路由
  • Java 侧无感知:各 AuthProvider 均调 NativeBridge,路由在 Rust 层完成
  • 双线 classpath 隔离BitAnswer 和 SelfHosted 不同 Maven 模块
  • 契约不变AuthProvider 接口 7 方法不变、AuthConfig record 不变
  • Schema 兼容selfhosted 段向后兼容扩展新字段

3. 许可证协议与数据模型

3.1 License JSON 结构

{
  "version": 1,
  "license_id": "01JQXYZ...",       // ULID
  "issued_at": "2026-05-18T10:00:00Z",
  
  // 载荷:AES-256-GCM 加密后的 Base64 密文
  // 解密后为 LicensePayload{ tenant_id, product, grant, constraints, features, custom }
  "payload": "A8f3Kd9s...base64url...",
  
  "signature": {
    "algorithm": "RS256",
    "key_id": "kp_2026_q2",         // 支持密钥轮换
    "value": "MEUCIQDx..."          // RS256 签名(对密文 payload 签名)
  }
}

3.2 LicensePayload(解密后明文)

{
  "tenant_id": "craftlabs-wharf-prod",
  "product": "wharf-inspection-v2",
  
  "grant": {
    "type": "perpetual",              // perpetual | subscription | trial
    "not_before": "2026-05-01T00:00:00Z",
    "not_after": "2027-05-01T00:00:00Z",
    "offline_grace_days": 7,
    "heartbeat_interval_hours": 24
  },
  
  "constraints": {
    "max_devices": 5,
    "max_concurrent_users": 0,        // 0=不限制
    "max_activations": 0
  },
  
  "features": {
    "advanced_analytics": true,
    "real_time_monitor": false,
    "api_export": true
  },
  
  "custom": {                         // 扩展字段
    "contract_ref": "CT-2026-0042",
    "project_id": "wharf-nansha-phase2"
  }
}

3.3 签发与校验流程

签发(服务器侧):
  LicensePayload 明文
    → AES-256-GCM 加密(key = HKDF(编译期盐, license_id)
    → 密文 payload (Base64)
    → RSA-SHA256 签名(对密文签名)
    → 完整 license.json

校验(Rust SDK 侧):
  license.json
    → RSA 公钥验签(快速排除伪造)
    → HKDF 派生 AES 密钥
    → AES-256-GCM 解密
    → 时间窗口校验(not_before ≤ now ≤ not_after + 离线宽限期)
    → 特性/约束校验

3.4 在线交互协议

端点:license-webhook-ingress:8081/license/v1/*

端点 方法 请求体 成功响应 错误响应
/activate POST {license_key, device_fingerprint} 200 {status:"activated", device_id, license_payload} 409 终端满 / 403 已吊销 / 422 无效
/heartbeat POST {license_key, device_hash, local_time} 200 {status:"ok", lease_renewed_until} 410 已过期/吊销
/check POST {license_key, device_hash} 200 {status:"valid", features, not_after} 410 已过期/吊销
/release POST {license_key, device_hash} 200 {status:"released"}

防重放:每个请求携带 X-Craft-NonceX-Craft-TimestampX-Craft-SignatureHMAC-SHA256),服务器时间窗口 5 分钟 + Nonce 去重。

3.5 签发端点(API 侧)

POST   /api/v1/licenses              # 创建/签发许可证
GET    /api/v1/licenses              # 分页查询
GET    /api/v1/licenses/{licenseId}  # 详情
POST   /api/v1/licenses/{id}/revoke  # 吊销
GET    /api/v1/licenses/{id}/activations  # 激活记录
POST   /api/v1/licenses/{id}/activations/{aid}/release  # 释放设备

3.6 数据库表(新增)

用途
platform_licenses 许可证主表(license_id、有效期、约束、状态、签名快照)
platform_license_features 特性开关(license_id, feature_key, enabled
platform_license_activations 终端激活记录(license_id, device_hash, stability_score, status
platform_license_heartbeats 心跳审计(可选,视量级)
platform_license_keys RSA 密钥对管理(key_id, public_key, private_key
platform_license_policies 策略模板(默认有效期、终端数、特性等)

4. Rust 层核心逻辑

4.1 新增依赖

reqwest = { version = "0.12", features = ["json", "rustls-tls"], default-features = false }
rsa = { version = "0.9", features = ["sha2"] }
aes-gcm = "0.10"
hkdf = "0.12"
base64 = "0.22"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
chrono = { version = "0.4", features = ["serde"] }

4.2 关键数据结构

pub struct DeviceFingerprint {
    pub composite_hash: String,    // SHA-256(layer1|layer2|layer3|layer4)
    pub stability_score: u8,       // 0~100,影响匹配策略
    pub layers: Vec<FingerprintLayer>,
}

pub struct LicenseStatus {
    pub licensed: bool,
    pub not_after: Option<i64>,
    pub features: HashMap<String, bool>,
    pub device_count: u32,
    pub max_devices: u32,
    pub heartbeat_due: Option<i64>,
}

4.3 硬件指纹分层采集

层级 权重 来源
Layer 1 硬件 40 Linux: DMI product_uuid / Windows: SMBIOS UUID / macOS: IOPlatformUUID
Layer 2 OS 30 Linux: /etc/machine-id / Windows: MachineGuid / macOS: 同 L1
Layer 3 存储 20 根文件系统 UUID (blkid/VolumeSerialNumber)
Layer 4 网络 10 物理网卡 MAC(跳过 docker/tap/lo/veth

稳定度评分Layer1=有+Layer2=有 → 70(强指纹);仅 Layer2 有 → 40;仅 Layer4 → 10。

兜底:稳定度 < 20 时,服务器分配 UUID 并加密存储到 ~/.craftlabs/device_id,管理员可手动吊销释放配额。

4.4 离线宽限期

fn check_license离线(&self) -> Result<LicenseStatus, LicenseError> {
    // 1. 加载缓存许可证
    // 2. 检查距离上次在线心跳的天数
    // 3. 超过 offline_grace_days → OfflineGraceExceeded
    // 4. 未超过 → 时间窗口校验(not_before/not_after
    // 5. 返回 LicenseStatusdevice_count=0 标记离线)
}

4.5 错误码体系

pub enum LicenseError {
    // 通用
    Success, ConfigMissing, Network, NotInitialized,
    // 签名/加密
    InvalidFormat, InvalidSignature, SignatureMismatch, CryptoError,
    DecryptionFailed, CorruptedPayload, LicenseIdMismatch,
    // 许可状态
    NotYetValid, Expired, NoCachedLicense,
    OfflineGraceExceeded { days_offline, max_days },
    InvalidLicense, LicenseRevoked,
    DeviceLimitReached, ConcurrentUserLimitReached, ActivationLimitReached,
    // 兼容比特
    BitAnswerStatus(u32),
    UnknownStatus(u16),
}

4.6 本地缓存

~/.craftlabs/
├── device_id              # 硬件指纹或服务器 UUID
├── license_cache.json     # AES-256-GCM 加密的许可证副本
│                          # 加密密钥 = SHA256(device_id + EMBEDDED_SALT)
└── heartbeat_state.json   # { last_heartbeat, lease_until }

4.7 编译期公钥嵌入

build.rs 读取 native/craft-core/embedded/pubkey.pem,生成 const EMBEDDED_PUBLIC_KEY: &str = "..."crypto.rsinitialize 时解析为 RsaPublicKey


5. 平台后端变更

5.1 delivery-platform-api 新增模块

license/
├── LicenseController.java        # REST /api/v1/licenses
├── LicenseService.java            # 签发/吊销/查询
├── LicenseSigner.java             # RSA+AES 签发
└── LicenseKeyManager.java         # 密钥对管理

persistence/license/
├── PlatformLicense.java & Mapper
├── PlatformLicenseFeature.java & Mapper
├── PlatformLicenseActivation.java & Mapper
├── PlatformLicenseKey.java & Mapper
└── PlatformLicensePolicy.java & Mapper

新增角色:LICENSE_OPS,管理 /api/v1/licenses/** 的写权限。

5.2 license-webhook-ingress 新增模块

license/
├── LicenseController.java         # /license/v1/*
├── LicenseActivateService.java    # 激活 + 终端匹配
├── LicenseHeartbeatService.java   # 心跳 + 吊销检测
├── LicenseCheckService.java       # 在线校验
├── LicenseReleaseService.java     # 设备释放
├── DeviceMatcher.java             # 分层指纹匹配
└── NonceValidator.java            # 防重放

5.3 事件回调

激活/心跳失败/到期/吊销等事件,沿现有 Webhook→API 异步投递链路通知 API 更新台账和审计。


6. 安全设计

6.1 许可证防篡改

措施 作用
载荷 AES-256-GCM 加密 阻止直接查看许可证内容(特性/期限/终端数),每个 license_id 独立密钥防批量破解
密文 RSA-SHA256 签名 验签不通过 = 篡改,先行快速拒绝
HKDF 密钥派生 盐编译期嵌入 + license_id,增加逆向提取难度
公钥编译期嵌入 不在运行时从文件或网络加载,防替换攻击

6.2 SDK 在线交互安全

措施 说明
TLS 全链路 HTTPS,证书校验
HMAC 签名 每个请求 X-Craft-Signature = HMAC-SHA256(nonce
Nonce 去重 Redis SETNX + 时间窗口 5 分钟,防重放
Authorization 头 Bearer tenantKey 双向验证

6.3 运行时保护

Rust 侧复用现有 security/ 模块:反调试检测、完整性校验、字符串混淆,适配自研路径。


7. 实施阶段

Phase 1:离线核心

目标:管理员签发 → 文件交付 → SDK 本地验签解密

  • Rust: crypto.rs、license.rs、cache.rs、device.rs、error.rs
  • Java: SelfhostedConfigSection 扩展字段
  • 平台: 数据库迁移、LicenseSigner、LicenseController(签发/查询/吊销)
  • 验证: AES 往返测试、RSA 验签测试、过期拒绝测试

Phase 2:在线激活

目标:SDK 网络激活获取许可证,终端配额限制

  • Rust: activate.rs、protocol.rs、trait_provider.rs、reqwest 集成
  • Webhook: LicenseController、ActivateService、DeviceMatcher、NonceValidator
  • 平台: 终端释放端点
  • 验证: Mock HTTP 测试、终端满 409 测试

Phase 3:心跳 + 离线兜底

目标:心跳维持租约、离线宽限期降级、吊销远程生效

  • Rust: heartbeat.rs、check_license 离线逻辑
  • Webhook: HeartbeatService、CheckService、ReleaseService
  • 验证: 心跳成功更新租约、断网 8 天 OfflineGraceExceeded、吊销后 410

Phase 4:完善与生产加固

目标:双 Provider 切换、CI/CD、文档

  • Rust: build.rs 公钥嵌入、security 模块适配
  • Java: MultiProviderSmokeTest、SelfHostedProviderTest
  • CI: ci-native.yml 适配、ci-platform.yml 新增
  • 文档: 集成指南、操作手册、CHANGELOG

工作量估算

Phase Rust Java SDK Platform API Webhook 合计
P1 M S M M~L
P2 M S M M
P3 S M M
P4 S S S

S=小,M=中,L=大)