mirror of
https://github.com/hpd840321/craftlabs-authorization-sdk.git
synced 2026-06-09 01:50:30 +08:00
feat: add native/Java auth SDK, docs, CI, and examples
Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
name: ci-java
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
pull_request:
|
||||
branches: [main, master]
|
||||
|
||||
jobs:
|
||||
maven:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "17"
|
||||
cache: maven
|
||||
- name: Build native (.so)
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential cmake
|
||||
cmake -S native -B native/build -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build native/build --parallel
|
||||
- name: Maven verify
|
||||
run: mvn -f java/pom.xml -B verify
|
||||
env:
|
||||
LD_LIBRARY_PATH: ${{ github.workspace }}/native/build
|
||||
@@ -0,0 +1,40 @@
|
||||
name: ci-native
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
pull_request:
|
||||
branches: [main, master]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK (JNI)
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "17"
|
||||
- name: Configure & build (Unix)
|
||||
if: runner.os != 'Windows'
|
||||
run: |
|
||||
cmake -S native -B native/build -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build native/build --parallel
|
||||
- name: Configure & build (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
cmake -S native -B native/build -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build native/build --config Release --parallel
|
||||
- name: Test (Unix)
|
||||
if: runner.os != 'Windows'
|
||||
working-directory: native/build
|
||||
run: ctest --output-on-failure
|
||||
- name: Test (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
working-directory: native/build
|
||||
run: ctest -C Release --output-on-failure
|
||||
@@ -0,0 +1,16 @@
|
||||
name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
jobs:
|
||||
placeholder:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Tag pushed
|
||||
run: |
|
||||
echo "Release workflow placeholder — attach native ZIP & Maven publish in later milestone."
|
||||
echo "Ref ${GITHUB_REF}"
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Build
|
||||
**/build/
|
||||
**/target/
|
||||
**/out/
|
||||
cmake-build-*/
|
||||
|
||||
# Java
|
||||
*.class
|
||||
*.jar
|
||||
*.war
|
||||
*.iml
|
||||
.idea/
|
||||
.settings/
|
||||
.project
|
||||
.classpath
|
||||
|
||||
# Native
|
||||
*.o
|
||||
*.obj
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
*.a
|
||||
*.lib
|
||||
*.exp
|
||||
*.pdb
|
||||
|
||||
# OS / IDE
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
.vscode/
|
||||
|
||||
# Maven
|
||||
dependency-reduced-pom.xml
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
.venv/
|
||||
venv/
|
||||
@@ -0,0 +1,147 @@
|
||||
# 比特授权云:机制与授权模式梳理
|
||||
|
||||
> 依据公开文档站点整理,主要页面入口:[欢迎页](https://doc.bitanswer.cn/docs/welcome/)、[授权模式分类](https://doc.bitanswer.cn/category/docs/license-models/)、[客户端 API](https://doc.bitanswer.cn/category/docs/client-api/)、[授权设计与创建](https://doc.bitanswer.cn/docs/function/licensing-design-creation/)、[基本授权过程](https://doc.bitanswer.cn/docs/application-development/development-process/)、[SDK 概述](https://doc.bitanswer.cn/docs/client-api/sdk-overview/)。
|
||||
> 整理日期:2026-04-06
|
||||
|
||||
---
|
||||
|
||||
## 1. 总体机制:控制台与产品模型
|
||||
|
||||
比特授权云将「卖什么、怎么控、怎么发到客户端」拆成多层概念:
|
||||
|
||||
|
||||
| 概念 | 作用 |
|
||||
| ---------------- | -------------------------------------------------------------- |
|
||||
| **产品(Product)** | 对应一套或一组软件;内建 **特征项(功能/加密点)** 与 **配置项(小型安全存储,键值字符串)**。 |
|
||||
| **模版(Template)** | 产品特征项的**子集**,常对应一个发行版本(如「简单版 / 专业版」)。 |
|
||||
| **业务(Business)** | 定义**商业模式 + 授权类型**(云、集团、单机浮动、演示、帐号等)及各类**授权属性**(有效期、终端数、离线策略等)。 |
|
||||
| **授权码 SN** | 16 位全球唯一标识;用户付费后发放;客户端用 SN 做激活、续期、升级。 |
|
||||
|
||||
|
||||
集成侧:**库文件与头文件与产品绑定**,混用会导致 `**Login` 返回 0x105**(文档明确说明)。
|
||||
|
||||
典型流程:规划功能与模块 → 控制台建立产品与模版 → 下载对应开发模块 → 建立业务 → 生成并分发授权码 → 客户端激活与运行时校验。
|
||||
|
||||
### 1.1 保护方式与平台
|
||||
|
||||
- **保护方式**:[欢迎页](https://doc.bitanswer.cn/docs/welcome/) 说明提供 **API** 与 **外壳** 两种;可组合使用以提高安全性。
|
||||
- **平台**:Windows(32/64)、Linux(含 ARM/x86)、macOS、Android、iOS 等;其它语言可通过动态库集成。
|
||||
|
||||
---
|
||||
|
||||
## 2. SDK 侧:与模式无关的共性(运行时语义)
|
||||
|
||||
来源:[SDK 概述](https://doc.bitanswer.cn/docs/client-api/sdk-overview/)
|
||||
|
||||
|
||||
| 名词 | 含义 |
|
||||
| --------------------- | ----------------------------------------- |
|
||||
| **资源** | 需要保护或控制的功能或数据单元。 |
|
||||
| **授权** | 将资源访问权下放给设备或用户。 |
|
||||
| **激活** | 将设备/用户与权限绑定(典型:在线更新许可,再登录)。 |
|
||||
| **授权升级** | 增加或减少资源访问权限。 |
|
||||
| **授权检查** | 检查是否拥有某资源权限。 |
|
||||
| **授权文件 / License 文件** | **单机类**授权保存在设备本地的许可数据。 |
|
||||
| **特征项** | 与程序中「加密点 / 功能开关」对应;可有版本;类型包括只读、读写、算法、密钥等。 |
|
||||
| **内存授权** | 将已有 License 传入 API 校验,**无激活过程**。 |
|
||||
|
||||
|
||||
文档强调:在**集团授权**场景下,**QueryFeature** 与 **ReleaseFeature** 应**成对**调用(占用与释放模块用户数)。
|
||||
|
||||
示例主流程(文档 C 示例):`Bit_Login(..., BIT_MODE_AUTO)` → 失败则输入 SN → `Bit_UpdateOnline` 激活 → 再 `Bit_Login` → 结束 `Bit_Logout`。
|
||||
|
||||
---
|
||||
|
||||
## 3. 授权模式分述
|
||||
|
||||
文档中「本地授权」与「云授权」的区分要点:[云授权](https://doc.bitanswer.cn/docs/license-models/cloud-license/) 页指出,除云授权外,其它方式通常需向客户端发放与**硬件指纹绑定**的电子许可证,激活后往往**不必**再连授权服务器(云授权则运行时实时连网、授权数据不落客户端)。
|
||||
|
||||
### 3.1 云授权
|
||||
|
||||
- **文档**:[云授权](https://doc.bitanswer.cn/docs/license-models/cloud-license/)
|
||||
- **许可数据**:始终在云端;客户端不保存完整授权数据。
|
||||
- **标识**:**授权码 SN**;文档描述为同一 SN 同一时间仅一台计算机使用。验证时上传 **SN + 本机硬件指纹**。
|
||||
- **安全会话**:验证通过后握手,用产品预置密钥派生**会话密钥**,后续通讯加密(文档类比网银并强调更复杂)。
|
||||
- **心跳**:约 **每 20 分钟**与服务器心跳以保持会话。
|
||||
- **多进程**:同一客户端同一 SN 最多 **10 个进程**;控制台可管理在线状态。
|
||||
- **管控**:授权属性变更可对在线客户端快速生效。
|
||||
- **局限**:运行期通常需联网;文档提及 **云授权 2.0** 改善依赖并支持高优先级登录、短时离线等。
|
||||
- **业务属性**:使用时间、次数、有效期;可设终端限制等。
|
||||
|
||||
### 3.2 单机浮动授权
|
||||
|
||||
- **文档**:[单机浮动授权](https://doc.bitanswer.cn/docs/license-models/local-license/)
|
||||
- **运行期**:激活后一般**不连**外部授权服务器即可使用(与云授权对比)。
|
||||
- **激活**:客户端提交 **SN + 硬件指纹**,服务器验证后下发与本机绑定的**本地许可**;复制到其它机器不可用。
|
||||
- **许可存放**:本机;对比——集团授权在**集团服务器**,云授权在**云端**。
|
||||
- **常见业务属性**:
|
||||
- **离线 vs 智能连接**:完全离线,或联网时后台自动校验/升级且不打断用户。
|
||||
- **强制认证**:最大离线时长,到期必须再连服务器。
|
||||
- **安装限制**:激活次数上限(多客户端**共享**该次数池)。
|
||||
- **终端限制**:允许多少台机器激活。
|
||||
- **失效与恢复**:许可损坏、硬盘问题或硬件变更可致失效;可按规则重新下载许可(可能消耗安装次数或终端名额)。
|
||||
|
||||
### 3.3 集团授权
|
||||
|
||||
- **文档**:[集团授权](https://doc.bitanswer.cn/docs/license-models/group-license/)
|
||||
- **形态**:开发商**自建授权服务器**,对局域网或互联网用户做**并发**控制。
|
||||
- **控制台**:创建业务时选择「集团授权」;可配置**用户数(并发上限)**,默认描述为最多 **999** 并发。
|
||||
- **服务端组件**(需单独下载安装):
|
||||
- 集团服务安装程序 `bit_service.exe`(Windows 服务),默认端口 **8273**(通讯)、**8274**(Web 管理)。
|
||||
- **集团服务扩展模块(.EXT)**:与**产品绑定**,不可混用。
|
||||
- **集团授权管理中心**:浏览器访问,默认示例 `http://localhost:8274`。
|
||||
- **客户端**:需配置集团服务器地址(API 或配置文件),参见 [部署和配置客户端](https://doc.bitanswer.cn/docs/application-development/application-distribution/) 等文档。
|
||||
|
||||
### 3.4 比特 ID 授权
|
||||
|
||||
- **文档**:[比特 ID 授权](https://doc.bitanswer.cn/docs/license-models/bitid-license/)
|
||||
- **机制**:在**单机授权**基础上增加 **USB 比特 ID** 绑定;插硬件的机器才能正常使用。
|
||||
- **场景**:离线环境下便于带硬件换机;控制台可追踪、注销设备。
|
||||
|
||||
### 3.5 演示授权
|
||||
|
||||
- **文档**:[演示授权](https://doc.bitanswer.cn/docs/license-models/demo-license/)
|
||||
- **特点**:演示码可被**多台客户端重复使用**;有有效期(如 15–180 天);**重装无法**简单延长试用期;可改为正式 SN。
|
||||
- **数据**:激活需连授权中心,可统计演示用户量、分布等。
|
||||
- **归类**:文档说明为**本地授权**——激活后使用**不必**再连服务器。
|
||||
|
||||
### 3.6 帐号授权
|
||||
|
||||
- **文档**:[帐号授权](https://doc.bitanswer.cn/docs/license-models/account-license/)
|
||||
- **对象**:从设备授权扩展到**人/帐号**,常为**订阅**模式。
|
||||
- **集成路径**:
|
||||
1. **库直连**:`Bit_LoginByPassword`(业务 GUID、密钥、帐号、密码等)。
|
||||
2. **OIDC**(文档更推荐):托管登录页取得 `code` → `POST /oidc/token` 换 **access_token** → `Bit_LoginByToken`。
|
||||
- **实践建议**:认证模块(Launchpad)与主程序分离,token 传入主程序。
|
||||
|
||||
---
|
||||
|
||||
## 4. 授权设计与特征项、配置项(摘要)
|
||||
|
||||
来源:[授权设计与创建](https://doc.bitanswer.cn/docs/function/licensing-design-creation/)
|
||||
|
||||
- **业务可配维度**(随授权类型不同而变化)包括:连接类型、强制认证周期、安装限制、有效期、集团用户数、起止日期、使用次数、终端限制等。
|
||||
- **授权内容更新生效**:
|
||||
- **云授权**:可较快反映到客户端(文档称可无需重启应用)。
|
||||
- **集团 / 单机**:一般在客户端**下次连服务器**时同步;智能连接、强制认证会影响同步时机。
|
||||
- **特征项类型**:只读、读写、算法、密钥等;均支持 QueryFeature / ReleaseFeature;集团场景下成对调用尤其重要。
|
||||
- **配置项(Data)**:存配置与小数据,UTF-8;**不宜**替代特征项做安全控制;客户端可能有缓存,异常断电有丢失风险。
|
||||
|
||||
---
|
||||
|
||||
## 5. 模式对照表(便于与自研抽象对齐)
|
||||
|
||||
|
||||
| 维度 | 云授权 | 单机 / 演示 / 比特 ID(本地类) | 集团授权 | 帐号授权 |
|
||||
| ---- | ------------ | -------------------- | ---------- | --------------- |
|
||||
| 判定位置 | 云端实时 | 本地许可(可选定期/智能连网同步) | 集团服务器(并发) | 云端 + token/密码 |
|
||||
| 长期联网 | 一般需要 | 通常不强制(依业务属性) | 依部署与策略 | 登录/刷新时需要 |
|
||||
| 并发模型 | SN + 在线会话/心跳 | 终端数、安装次数等 | 并发用户数 | 订阅/帐号维度 |
|
||||
| 典型标识 | SN | SN(演示码策略特殊) | SN + 服务器地址 | 帐号 / OIDC token |
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 6. 免责声明
|
||||
|
||||
本文档为对 **doc.bitanswer.cn** 公开页面的**学习性整理**,不替代原厂文档;产品行为、默认值与 API 以官方网站与最新版本为准。
|
||||
@@ -0,0 +1,349 @@
|
||||
# 比特授权云:客户端 API 梳理(基于官方文档)
|
||||
|
||||
> 来源:[C 语言接口定义 v2](https://doc.bitanswer.cn/docs/client-api/c-interface-definitions-v2/)、[Java 语言接口 v2](https://doc.bitanswer.cn/docs/client-api/java-interface-v2/)、[SDK 概述](https://doc.bitanswer.cn/docs/client-api/sdk-overview/)、[典型场景](https://doc.bitanswer.cn/docs/client-api/examples-of-using-the-sdk/)。
|
||||
> 其它语言入口(文档中心列举):[Delphi](https://doc.bitanswer.cn/docs/client-api/delphi-interface/)、[C#](https://doc.bitanswer.cn/docs/client-api/csharp-interface/)、[VB.Net](https://doc.bitanswer.cn/docs/client-api/vb-net-interface/)、[VB6](https://doc.bitanswer.cn/docs/client-api/vb6-interface/)。
|
||||
> 整理日期:2026-04-06
|
||||
> **说明**:本文为对公开文档的**纲要式整理**,参数细节、错误码与边界条件以官方页面及随产品下发的 `bitanswer.h`/接口文件为准。
|
||||
> **本地对照**:已与仓库内手工备份的 C 接口 `[docs/c.md](c.md)`、Java 接口 `[docs/java.md](java.md)` 交叉核对(见文末「审核说明」及 **附录 A**)。
|
||||
|
||||
---
|
||||
|
||||
## 1. SDK 交付形态与前置条件
|
||||
|
||||
- **获取方式**:在比特授权云平台「模块下载」获取与**产品绑定**的静态库/动态库及接口定义;**不同产品库不可混用**(文档说明 `Login` 不匹配会返回 `0x105` 类错误)。
|
||||
- **C**:头文件 `bitanswer.h` + 平台库(文档示例如 `libxxx_xxx_x64.a`)。
|
||||
- **Java**:JNI + 主封装类 `**BitAnswer`**(方法名为 camelCase,语义与 C API 大体一一对应;签名与枚举见 **附录 A** / `[docs/java.md](java.md)`)。
|
||||
- **支持平台(SDK 概述列举)**:Windows、Linux、Android、ARM Linux、MIPS Linux、macOS、iOS、HarmonyOS、QNX 等。
|
||||
|
||||
**运行期共性概念(SDK 概述)**
|
||||
|
||||
|
||||
| 概念 | 含义 |
|
||||
| -------------------------- | ---------------------------------------------------------------------------------------- |
|
||||
| `application_data` / 产品识别码 | 编译进接口定义、与产品一一对应,多数 API 必填。 |
|
||||
| `BIT_HANDLE` / 会话句柄 | `Bit_Login` / `Bit_LoginEx` 等成功后返回,后续特征项/心跳等依赖此句柄。 |
|
||||
| `BIT_STATUS` | API 返回状态码;具体取值与错误码见官方「错误码」文档。 |
|
||||
| 授权文件默认目录(典型场景) | Linux:`{当前用户}/BitAnswer`;Windows:`{系统盘}/ProgramData/BitAnswer`;可用 `Bit_SetRootPath` 自定义。 |
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 2. URL / 地址约定(`Bit_Login` 的 `szURL` 等)
|
||||
|
||||
文档说明 `szURL` 可表达多种「授权来源」(节选):
|
||||
|
||||
|
||||
| 形式 | 含义 |
|
||||
| ----------------------------- | --------------------------------------------------------------------------------------- |
|
||||
| `bit://ip:port` | 集团授权服务地址。 |
|
||||
| `http://ip:port` | 授权服务中心(如云/E3 等)。 |
|
||||
| `root://路径` | 仅在该路径下查找授权,效果类似先 `Bit_SetRootPath`。 |
|
||||
| `lic://文件路径` / 目录 / License 串 | 内存或本地文件加载:`lic://` 可加载文件内容、目录下 `*.lic`、或直接传入 License 串;**多个路径用逗号分隔**(`c.md` 示例为半角 `,`)。 |
|
||||
| 简写 | 文档示例:`/tmp,/data,127.0.0.1:8273` 等与 `lic://...`/`bit://...` 组合等价写法。 |
|
||||
|
||||
|
||||
**配置优先级(文档)**:同一设置同时存在时 — **环境变量 > 调用 API 传入 > 配置文件**(`bit_config.xml`,典型场景详述多 `Server`/`Proxy` 节点)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 登录模式与标识(`LOGIN_MODE` / `LoginMode`)
|
||||
|
||||
与 `Bit_Login` / `Bit_LoginEx` 的 `mode` 为**按位组合**。文档列出的典型取值(C 名 / Java 名对应):
|
||||
|
||||
|
||||
| C(示意) | Java(示意) | 语义摘要 |
|
||||
| -------------------------------------- | --------------------------- | ------------------------------------ |
|
||||
| `BIT_MODE_LOCAL` | `LOCAL` | 仅本地(单机、BIT-ID、内存授权等)。 |
|
||||
| `BIT_MODE_REMOTE` | `REMOTE` | 仅远端(云、帐号、集团等)。 |
|
||||
| `BIT_MODE_AUTO` | `AUTO` | 本地与远端都尝试;**优先级:本地 > 远端**(在已配置远端前提下)。 |
|
||||
| `BIT_MODE_CACHE` | `CACHE` | 云授权 SN 缓存,便于下次免输 SN。 |
|
||||
| `BIT_MODE_USB` | `USB` | USB 相关授权。 |
|
||||
| `LOGIN_MODE_PROCESS` | `PROCESS` | **集团**:按进程占并发点;其它模式无效。 |
|
||||
| `LOGIN_MODE_SESSION` | `SESSION` | **集团**:更细粒度会话占点。 |
|
||||
| `LOGIN_MODE_HIGH_PRIORITY` | `HIGH_PR` | **云**:高优先级登录可挤占普通登录。 |
|
||||
| `LOGIN_MODE_NO_NETWORK` | `NO_NETWORK` | 禁止库联网。 |
|
||||
| `LOGIN_MODE_CHECK_USERNAME` | `CHECK_USERNAME` | **集团**:设备+用户名才视为同一点。 |
|
||||
| `LOGIN_MODE_USE_SESSIONID` | `USE_SESSIONID` | `Logout` 不释放点数,由第三方维护心跳。 |
|
||||
| `LOGIN_MODE_HIGH_PERFORMANCE` | `HIGH_PERFORMANCE` | **集团**:合并请求降负载。 |
|
||||
| `LOGIN_MODE_PERSISTENT_CONN` | `PERSISTENT_CONN` | **集团**长连接。 |
|
||||
| `LOGIN_MODE_CREATE_HANDLE_ONLY` | `CREATE_HANDLE_ONLY` | 仅创建句柄,**真正校验推迟到 Query**。 |
|
||||
| `LOGIN_MODE_CREATE_NEW_HANDLE` | `CREATE_NEW_HANDLE` | 每次唯一句柄,属性互不干扰。 |
|
||||
| `LOGIN_MODE_MID` / `ACCOUNT` / `GROUP` | `MID` / `ACCOUNT` / `GROUP` | 按设备、帐号、分组名占点等。 |
|
||||
|
||||
|
||||
C 示例中常写作 `LOGIN_MODE(BIT_MODE_REMOTE | LOGIN_MODE_HIGH_PERFORMANCE)` 等形式,即用 `LOGIN_MODE` 宏包装按位或(见 `c.md`)。
|
||||
|
||||
**szSN / sn 常见形态(文档)**:云平台 SN;`#0` / `#bitid:0` 等形式选 BIT-ID;`<口令>` 激活口令;`SN<口令>` 拼接;帐号授权可与密码类参数配合(具体见帐号授权专章)。
|
||||
|
||||
---
|
||||
|
||||
## 4. API 分组:认证与会话(C 名为主,Java 对照)
|
||||
|
||||
|
||||
| 功能 | C API | Java API(文档) |
|
||||
| ---------- | ------------------------------------------- | ----------------------------------- |
|
||||
| 登录 | `Bit_Login`, `Bit_LoginEx` | `login`, `loginEx` |
|
||||
| 帐号 Token | `Bit_LoginByToken`, `Bit_LoginByTokenEx` | `loginByToken`, `loginByTokenEx` |
|
||||
| 帐号密码 | `Bit_LoginByPassword` | `loginByPassword` |
|
||||
| 登出 | `Bit_Logout` | `logout` |
|
||||
| 浮动迁出 | `Bit_Revoke`(在线/离线迁出、请求码) | `revoke`, `revokeOnline` |
|
||||
| 删除本机 SN 数据 | `Bit_RemoveSn` | `removeSn` |
|
||||
| 手动心跳 | `Bit_Heartbeat`(10s 内最多触发一次等说明) | `heartbeat` |
|
||||
| Session 控制 | `Bit_SessionControl`, `Bit_SetSessionState` | `sessionControl`, `setSessionState` |
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 5. API 分组:激活与离线/在线升级
|
||||
|
||||
|
||||
| 功能 | C API | Java(`BitAnswer`,`docs/java.md`) |
|
||||
| -------- | ----------------------------------------------- | ----------------------------------------------------------------- |
|
||||
| 在线激活/升级 | `Bit_UpdateOnline` | `void updateOnline(String url, String sn)` |
|
||||
| 取升级请求串 | `Bit_GetRequestInfo`(绑定类型、设备码 `REQ_TYPE_MID` 等) | `String getRequestInfo(String sn, BindingType type)` |
|
||||
| 应用升级包 | `Bit_ApplyUpdateInfo` | `String applyUpdateInfo(String updateInfo)` |
|
||||
| 远程集团应用升级 | `Bit_ApplyUpdateInfoEx` | **`java.md` 未收录**;若需远程集团升级请以随包接口为准 |
|
||||
| 用请求串换升级码 | `Bit_GetUpdateInfo` | `String getUpdateInfo(String url, String sn, String requestInfo)` |
|
||||
|
||||
|
||||
**典型场景补充**
|
||||
|
||||
- **在线**:`Bit_UpdateOnline(NULL, sn, application_data)`;BIT-ID 可用 `#0` 等形式。
|
||||
- **离线**:本机 `Bit_GetRequestInfo` → 联网换取 License 串 → 本机 `Bit_ApplyUpdateInfo`;涉密场景可用**设备码**缩短人工传递长度。
|
||||
- **内存授权**:从离线包取 `<code>`,拼 `lic://...` 作为 `Bit_Login` 的 url,模式 `BIT_MODE_LOCAL`。
|
||||
|
||||
---
|
||||
|
||||
## 6. API 分组:特征项(功能模块与加密点)
|
||||
|
||||
|
||||
| 功能 | C API | Java API(文档) |
|
||||
| ------------ | ---------------------------------------------- | -------------------------------------- |
|
||||
| 批量 Query | `Bit_BatchBegin`, `Bit_BatchEnd` | `batchBegin`, `batchEnd` |
|
||||
| 基础占用/释放 | `Bit_QueryFeature`, `Bit_ReleaseFeature` | `queryFeature`, `releaseFeature` |
|
||||
| 集团扩展占用 | `Bit_QueryFeatureEx`, `Bit_ReleaseFeatureEx` | `queryFeatureEx`, `releaseFeatureEx` |
|
||||
| 按名称+版本/队列 | `Bit_QueryFeatureEx2`, `Bit_ReleaseFeatureEx2` | `queryFeatureEx2`, `releaseFeatureEx2` |
|
||||
| 查存在/有效期(不占点) | `Bit_GetFeatureInfo2`, `Bit_GetFeatureInfoEx2` | `getFeatureInfo2`, `getFeatureInfoEx2` |
|
||||
| Ticket 信息 | `Bit_GetTicketInfo` | `getTicketInfo` |
|
||||
| 算法特征 | `Bit_ConvertFeature` | `convertFeature` |
|
||||
| 密钥特征加解密 | `Bit_EncryptFeature`, `Bit_DecryptFeature` | `encryptFeature`, `decryptFeature` |
|
||||
| 读写特征值 | `Bit_ReadFeature`, `Bit_WriteFeature` | `readFeature`, `writeFeature` |
|
||||
|
||||
|
||||
文档强调:**集团授权**下 `QueryFeature` / `ReleaseFeature`(及 Ex 系列)需**成对**使用以正确占用/释放并发用户数;`QueryFeatureEx` 支持多种 `mode`(默认非阻塞、尽可能占用、仅检查计数等)。
|
||||
|
||||
---
|
||||
|
||||
## 7. API 分组:配置项(Data)
|
||||
|
||||
|
||||
| 功能 | C API | Java API(文档) |
|
||||
| ------- | ------------------------------------------- | ----------------------------------- |
|
||||
| 读 | `Bit_GetDataItem` | `getDataItem` |
|
||||
| 写/创建 | `Bit_SetDataItem` | `setDataItem` |
|
||||
| 枚举数量/名称 | `Bit_GetDataItemNum`, `Bit_GetDataItemName` | `getDataItemNum`, `getDataItemName` |
|
||||
| 删(授权码侧) | `Bit_RemoveDataItem` | `removeDataItem` |
|
||||
|
||||
|
||||
Java 文档对名称/值长度有简要限制说明(如名称最长 128 字节、值 1024 字节量级,以官方为准)。
|
||||
|
||||
---
|
||||
|
||||
## 8. API 分组:信息查询
|
||||
|
||||
与 `c.md` 中 **「信息获取」** 大节对应。该节除下表外,还包括版本/句柄/诊断等 API(为减少重复,详见 **§10**)。
|
||||
|
||||
|
||||
| 功能 | C API | 说明(摘要) |
|
||||
| ------- | -------------------- | ------------------------------------------------ |
|
||||
| 会话信息 | `Bit_GetSessionInfo` | XML 或字段型信息:SN/特征/配置项摘要、服务器时间、授权类型组合、起止日期、离线分钟数等。 |
|
||||
| 本机/环境信息 | `Bit_GetInfo` | 已激活 SN 列表、特征列表、集团服务器发现、BIT-ID 列表、升级错误详情等。 |
|
||||
| 集团服务信息 | `Bit_GetServerInfo` | **无需先 Login**;查集团侧授权/特征等 XML。 |
|
||||
|
||||
|
||||
**与 `c.md` 源码块核对**:`Bit_GetServerInfo` 小节内的函数名被写成 `Bit_GeServerInfo`(缺字母 `t`),与章节标题不一致,应视为复制/排版笔误;集成时以 **`bitanswer.h`** 为准。
|
||||
|
||||
---
|
||||
|
||||
## 9. API 分组:借出 / 归还(浮动与集团场景扩展)
|
||||
|
||||
文档在 C / Java 接口中均用「借出操作」类章节描述。**C** 名称见下左列;**Java(`BitAnswer`)** 见 [`docs/java.md`](java.md) 及下表。
|
||||
|
||||
|
||||
| C API | Java 方法(`docs/java.md`) |
|
||||
| ----------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| `Bit_GetBorrowRequest` | `String getBorrowRequest(String sn, int durationDay)` |
|
||||
| `Bit_GetBorrowFeatureRequest` | `String getBorrowFeatureRequest(int durationDay, String borrowScope)` |
|
||||
| `Bit_CheckOutSn` | `void checkOutSn(String url, int featureId)` |
|
||||
| `Bit_CheckOutSnEx` | `void checkOutSnEx(String url, int featureId, String xmlScope, int durationDays)` |
|
||||
| `Bit_CheckOut` | `void checkOut(String url, String scope, String featureList, int durationDays)` |
|
||||
| `Bit_CheckOutFeatures` | `void checkOutFeatures(String url, int[] featureList, int durationDays)` |
|
||||
| `Bit_CheckIn` | `void checkIn(String url, int featureId)` |
|
||||
| `Bit_CheckInEx` | `void checkInEx(String url, int featureId, String xmlScope)` |
|
||||
| `Bit_ApplyBorrowInfo` | `void ApplyBorrowInfo(String borrowInfo)`(文档锚点为大写 `ApplyBorrowInfo`;参数类型应以实际 SDK 的 `String` 为准) |
|
||||
|
||||
|
||||
参数语义、`scope` / `featureList` XML 格式等以原文为准。Java 文档注明 **applyUpdateInfo** 可兼容离线借出串(与 `ApplyBorrowInfo` 重叠场景见原文)。
|
||||
|
||||
---
|
||||
|
||||
## 10. API 分组:路径、代理、属性与其它工具
|
||||
|
||||
对应 `c.md` 中 **「信息获取」** 后半(`Bit_GetVersion` 起)与 **「属性设置」** 全节。常见于部署与诊断:
|
||||
|
||||
|
||||
| C API | 用途摘要 |
|
||||
| ----------------------------------- | ------------------- |
|
||||
| `Bit_SetRootPath` | 授权文件根路径。 |
|
||||
| `Bit_SetProxy` | HTTP/SOCKS 等代理参数。 |
|
||||
| `Bit_SetLocalServer` | 本地/集团服务发现相关设置(见原文)。 |
|
||||
| `Bit_GetProductPath` | 产品路径查询。 |
|
||||
| `Bit_GetVersion` | 库版本。 |
|
||||
| `Bit_GetLastError` | 上一 API 错误码。 |
|
||||
| `Bit_GetNextHandle` | 枚举/遍历句柄(见原文)。 |
|
||||
| `Bit_SetAttr` / `Bit_SetCustomInfo` | 句柄/会话属性与自定义信息。 |
|
||||
| `Bit_TestBitService` | 探测集团服务等可达性。 |
|
||||
|
||||
**Java(`docs/java.md`)对应**:`int getVersion()` · `String getProductPath()` · `int getLastError()` · `void testBitService(String url, String sn, int featureId)` · `void setRootPath(String rootPath)` · `void setLocalServer(String hostName, int port, int timeout)` · `void setProxy(String hostName, int port, String userId, String password)` · `void setAttr(int type, byte[] pValue)` · `void setCustomInfo(...)`(`String` / `int` 重载)。**未在 `java.md` 列出**:`Bit_GetNextHandle` 的 Java 对等方法(若需遍历句柄请查随包 JNI 或新版文档)。
|
||||
|
||||
---
|
||||
|
||||
## 附录 A:Java `BitAnswer` API(依据 [`docs/java.md`](java.md))
|
||||
|
||||
### A.1 类型与构造
|
||||
|
||||
| 项 | 说明 |
|
||||
|----|------|
|
||||
| **主类** | `BitAnswer`(实例方法;通过 JNI 调用 native,与 C SDK 同库) |
|
||||
| **构造方法** | `BitAnswer()`;`BitAnswer(String url, String sn, LoginMode mode)`(便捷构造,等价于再调用 `login` 的用法以官方示例为准) |
|
||||
| **错误处理** | 多数 API 为 `void` 或返回数据;`int getLastError()` 返回**当前线程**最近一次调用的错误码(成功为 `0`,见 `java.md`) |
|
||||
|
||||
### A.2 文档中出现的枚举 / 参数类型(用于方法签名)
|
||||
|
||||
| 名称 | 用途(节选) |
|
||||
|------|----------------|
|
||||
| `LoginMode` | `login` / `loginEx`、构造器第三参数;与 C 侧 `LOGIN_MODE` 按位语义对应,Java 侧为枚举常量(`LOCAL`、`REMOTE`、`AUTO`、`CACHE`、`USB`、`PROCESS`、`SESSION`、`HIGH_PR`、`NO_NETWORK`、`CHECK_USERNAME`、`USE_SESSIONID`、`HIGH_PERFORMANCE`、`PERSISTENT_CONN`、`CREATE_HANDLE_ONLY`、`CREATE_NEW_HANDLE`、`MID`、`ACCOUNT`、`GROUP`) |
|
||||
| `BindingType` | `getRequestInfo`:`EXISTING`、`LOCAL`、`USB_STORAGE` |
|
||||
| `BatchMode` | `batchBegin`:`BIT_BATCH_MODE_CONTINUE`、`BIT_BATCH_MODE_BREAK` |
|
||||
| `SessionType` | `getSessionInfo`:`XML_TYPE_SN_INFO`、`XML_TYPE_FEATURE_INFO`、`XML_TYPE_DATA_INFO`、`BIT_SERVER_ADDRESS`、`BIT_SERVER_TIME`、`BIT_CONTROL_TYPE` 及各日期/次数/离线字段常量(见 `java.md`) |
|
||||
| `InfoType` | `getInfo`:`BIT_INFO_SERVER_ADDRESS`、`BIT_INFO_SN`、`BIT_INFO_SN_FEATURE` 等 |
|
||||
| `ServerInfoType` | `getServerInfo`:`BIT_SERVER_INFO_SN`、`BIT_SERVER_INFO_SN_FEATURE`、`BIT_SERVER_INFO_SN_LICENSE` 等 |
|
||||
| `SessionCtlType` | `sessionControl`:`SESSION_CTL_LOGOUT`、`SESSION_CTL_CHECK` |
|
||||
| **`setAttr` 的 type** | `ATTR_HB_RETRY_FAILED_CALLBACK`、`ATTR_WAIT_TIMEOUT`、`ATTR_RETRY_COUNT` 等(见 `java.md`) |
|
||||
| **`setCustomInfo` 的 infoId** | `CustomInfo`:`CUSTOM_CLIENT_ID`、`CUSTOM_OPTION` 等(`java.md` 列至 `CUSTOM_GROUP_NAME(0xA)`) |
|
||||
|
||||
### A.3 方法签名全表(与 C 对照)
|
||||
|
||||
**认证**
|
||||
|
||||
| Java |
|
||||
|------|
|
||||
| `void login(String url, String sn, LoginMode mode)` |
|
||||
| `void loginEx(String url, String sn, int featureId, String xmlScope, LoginMode mode)` |
|
||||
| `void loginByToken(String url, String token)` |
|
||||
| `void loginByTokenEx(String url, String businessGuid, String token, String idpGuid, String grantType)` |
|
||||
| `void loginByPassword(String url, String guid, String secret, String account, String password)` |
|
||||
| `void logout()` |
|
||||
| `String revoke(String sn)` |
|
||||
| `void revokeOnline(String url, String sn)` |
|
||||
| `void removeSn(String sn)` |
|
||||
| `int heartbeat()` |
|
||||
| `String sessionControl(String url, String sessionId, SessionCtlType type)` |
|
||||
| `void setSessionState(int state, byte[] pReserved)` |
|
||||
|
||||
**激活升级**(另见 **§5** 表格)
|
||||
|
||||
**特征项**
|
||||
|
||||
| Java |
|
||||
|------|
|
||||
| `void batchBegin(BatchMode mode)` · `int[] batchEnd()` |
|
||||
| `int queryFeature(int featureId)` · `int releaseFeature(int featureId)` |
|
||||
| `int queryFeatureEx(int featureId, int mode, int required, String scope)` · `int releaseFeatureEx(int featureId, int consumed, String scope)` |
|
||||
| `long queryFeatureEx2(String featureName, int mode, int required, String scope)` · `void releaseFeatureEx2(byte[] ticket, int consumed)` |
|
||||
| `int getFeatureInfo2(String featureName, String scope)` · `String getFeatureInfoEx2(String featureName, String scope)` |
|
||||
| `String getTicketInfo(byte[] ticket, int type)`(`type` 如 `BIT_TICKET_TYPR_USERS`,原文档拼写如此) |
|
||||
| `int convertFeature(int featureId, int para1, int para2, int para3, int para4)` |
|
||||
| `byte[] encryptFeature(int featureId, byte[] pPlainBuffer)` · `byte[] decryptFeature(int featureId, byte[] pCipherBuffer)` |
|
||||
| `int readFeature(int featureId)` · `void writeFeature(int featureId, int featureValue)` |
|
||||
|
||||
**配置项**
|
||||
|
||||
| Java |
|
||||
|------|
|
||||
| `byte[] getDataItem(String dataItemName)` · `void setDataItem(String dataItemName, byte[] dataItemValue)` |
|
||||
| `int getDataItemNum()` · `String getDataItemName(int index)` · `void removeDataItem(String dataItemName)` |
|
||||
|
||||
(`java.md`:配置项名称最大 128 字节等限制与 C 侧一致。)
|
||||
|
||||
**信息获取**
|
||||
|
||||
| Java |
|
||||
|------|
|
||||
| `String getSessionInfo(SessionType type)` · `String getInfo(String sn, InfoType type)` |
|
||||
| `String getServerInfo(String url, String sn, String scope, ServerInfoType type)` |
|
||||
| `int getVersion()` · `void testBitService(String url, String sn, int featureId)` · `String getProductPath()` · `int getLastError()` |
|
||||
|
||||
**借出操作**(另见 **§9** 表)
|
||||
|
||||
### A.4 与 C 覆盖差异(据 `docs/java.md` 全文)
|
||||
|
||||
| C API | Java(`docs/java.md`) |
|
||||
|-------|------------------------|
|
||||
| `Bit_ApplyUpdateInfoEx` | 未收录 |
|
||||
| `Bit_GetNextHandle` | 未收录 |
|
||||
|
||||
**补充**:C 侧 `Bit_GetRequestInfo` 的 `BINDING_TYPE` 含 **`REQ_TYPE_MID`(设备码)**;`java.md` 在 `getRequestInfo` 的 `BindingType` 中仅列出 `EXISTING`、`LOCAL`、`USB_STORAGE`。设备码流程在 Java 是否另有接口,以 **随包 SDK / 更新版 `java.md`** 为准。
|
||||
|
||||
### A.5 文档小瑕疵(复制源)
|
||||
|
||||
- `loginEx` 说明中「Login 等价于 LoginEx」与 C 页类似,易误解;需包含**指定 featureId** 时用 `loginEx`。
|
||||
- `batchBegin` 正文写「由 **Bit_batchEnd** 提交」应为 **`batchEnd`(Java)** / **`Bit_BatchEnd`(C)**。
|
||||
- `ApplyBorrowInfo` 参数写 `string` 应为 Java **`String`**。
|
||||
|
||||
---
|
||||
|
||||
## 11. C API 名称索引(供检索)
|
||||
|
||||
下列名称与 `c.md` 中全部 `## [Bit_…]` 小节一致,共 **59** 个独立函数(其中 `Bit_CheckOutSn` / `Bit_CheckOutSnEx` 合并在同一文档小节)。若与头文件有出入以 **`bitanswer.h`** 为准:
|
||||
|
||||
`Bit_ApplyBorrowInfo` · `Bit_ApplyUpdateInfo` · `Bit_ApplyUpdateInfoEx` · `Bit_BatchBegin` · `Bit_BatchEnd` · `Bit_CheckIn` · `Bit_CheckInEx` · `Bit_CheckOut` · `Bit_CheckOutFeatures` · `Bit_CheckOutSn` · `Bit_CheckOutSnEx` · `Bit_ConvertFeature` · `Bit_DecryptFeature` · `Bit_EncryptFeature` · `Bit_GetBorrowFeatureRequest` · `Bit_GetBorrowRequest` · `Bit_GetDataItem` · `Bit_GetDataItemName` · `Bit_GetDataItemNum` · `Bit_GetFeatureInfo2` · `Bit_GetFeatureInfoEx2` · `Bit_GetInfo` · `Bit_GetLastError` · `Bit_GetNextHandle` · `Bit_GetProductPath` · `Bit_GetRequestInfo` · `Bit_GetServerInfo` · `Bit_GetSessionInfo` · `Bit_GetTicketInfo` · `Bit_GetUpdateInfo` · `Bit_GetVersion` · `Bit_Heartbeat` · `Bit_Login` · `Bit_LoginEx` · `Bit_LoginByPassword` · `Bit_LoginByToken` · `Bit_LoginByTokenEx` · `Bit_Logout` · `Bit_QueryFeature` · `Bit_QueryFeatureEx` · `Bit_QueryFeatureEx2` · `Bit_ReadFeature` · `Bit_ReleaseFeature` · `Bit_ReleaseFeatureEx` · `Bit_ReleaseFeatureEx2` · `Bit_RemoveDataItem` · `Bit_RemoveSn` · `Bit_Revoke` · `Bit_SessionControl` · `Bit_SetAttr` · `Bit_SetCustomInfo` · `Bit_SetDataItem` · `Bit_SetLocalServer` · `Bit_SetProxy` · `Bit_SetRootPath` · `Bit_SetSessionState` · `Bit_TestBitService` · `Bit_UpdateOnline` · `Bit_WriteFeature`
|
||||
|
||||
---
|
||||
|
||||
## 12. 与mgmt/运营侧 API 的边界
|
||||
|
||||
开发者控制台还提供 **[Backoffice API](https://doc.bitanswer.cn/category/docs/backoffice-api/)**(REST/数据结构),用于授权码、用户、业务等**服务端自动化**,与上表**客户端安全库 API** 不同层。若需「控制台可调用的 HTTP API」,请单独以 Backoffice 文档为准。
|
||||
|
||||
---
|
||||
|
||||
## 13. 免责声明
|
||||
|
||||
本文档不替代比特授权云官方文档与随 SDK 发布的法律/技术支持条款;集成与合规问题请咨询官方渠道。
|
||||
|
||||
---
|
||||
|
||||
## 14. 对照本地备份的审核结论(2026-04-06)
|
||||
|
||||
### 14.1 `docs/c.md`
|
||||
|
||||
| 项 | 结论 |
|
||||
|----|------|
|
||||
| **函数覆盖** | `c.md` 中列出的全部 Bit 客户端 API 均已在本梳理的分组或 §11 索引中覆盖;**无遗漏**。 |
|
||||
| **章节结构** | 「信息获取」后半与「属性设置」对应 §8 / §10,表头已说明。 |
|
||||
| **Bit_GetServerInfo** | `c.md` 代码块误写为 `Bit_GeServerInfo`;§8 已注释。 |
|
||||
| **Bit_LoginEx 说明** | `c.md` 中 `featured=0` 等笔误;本梳理未复述。 |
|
||||
| **多路径分隔符** | 已标明示例为半角 `,`。 |
|
||||
| **登录模式** | 与 `c.md` 表一致;已补充 `LOGIN_MODE(...)` 宏。 |
|
||||
| **§11 索引** | 以 `c.md` 小节为对齐基准。 |
|
||||
|
||||
### 14.2 `docs/java.md`
|
||||
|
||||
| 项 | 结论 |
|
||||
|----|------|
|
||||
| **对等性** | `java.md` 中 **`BitAnswer` 实例方法**与 C API 基本全覆盖;**附录 A** 为完整签名与枚举清单。 |
|
||||
| **缺失相对 C** | `Bit_ApplyUpdateInfoEx`、`Bit_GetNextHandle` 在 `java.md` 中未出现(§A.4)。 |
|
||||
| **`getServerInfo`** | Java 文档写为 `getServerInfo`;无 C 页 `GeServerInfo` 笔误问题。 |
|
||||
| **借出** | §9 已按 `java.md` 补全 `checkOut*` / `checkIn*` / `ApplyBorrowInfo` 等 Java 方法表。 |
|
||||
|
||||
|
||||
+1202
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* C++ 调用示例:初始化、校验许可、销毁句柄。
|
||||
*
|
||||
* 版权所有 © 广州创飞人工智能技术有限公司
|
||||
* 开发者:huangping@craftlabs.cn
|
||||
*/
|
||||
#include "craftlabs_auth.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
int main() {
|
||||
AuthHandle h = auth_initialize("{}");
|
||||
if (!h) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
AuthResult r = auth_check_license(h);
|
||||
if (r.success == 0) {
|
||||
auth_destroy(h);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auth_destroy(h);
|
||||
std::printf("example cpp ok\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import cn.craftlabs.auth.AuthProvider;
|
||||
import cn.craftlabs.auth.AuthResult;
|
||||
import cn.craftlabs.auth.bitanswer.BitAnswerProvider;
|
||||
|
||||
/**
|
||||
* 演示:通过 {@link BitAnswerProvider} 完成初始化与许可校验。
|
||||
*
|
||||
* <p>版权所有 © 广州创飞人工智能技术有限公司
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
public class ExampleApp {
|
||||
public static void main(String[] args) {
|
||||
try (AuthProvider p = new BitAnswerProvider()) {
|
||||
AuthResult r = p.initialize("{}");
|
||||
System.out.println("init: " + r.isSuccess() + " " + r.getMessage());
|
||||
r = p.checkLicense();
|
||||
System.out.println("check: " + r.isSuccess() + " " + r.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
"""示例:设置 CRAFTLABS_AUTH_LIBRARY 或 PYTHONPATH 后运行。
|
||||
|
||||
版权所有 © 广州创飞人工智能技术有限公司
|
||||
开发者:huangping@craftlabs.cn
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
sys.path.insert(0, os.path.join(ROOT, "python"))
|
||||
|
||||
from craftlabs_auth import AuthApi # noqa: E402
|
||||
|
||||
|
||||
def main() -> None:
|
||||
lib = os.path.join(ROOT, "native", "build", "libcraftlabs_auth_bitanswer.so")
|
||||
if os.path.isfile(lib):
|
||||
os.environ.setdefault("CRAFTLABS_AUTH_LIBRARY", lib)
|
||||
|
||||
with AuthApi() as api:
|
||||
print(api.initialize("{}"))
|
||||
print(api.check_license())
|
||||
print(api.get_license_info())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.craftlabs</groupId>
|
||||
<artifactId>craftlabs-auth-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>craftlabs-auth-bitanswer</artifactId>
|
||||
<name>CraftLabs Auth — Bitanswer adapter</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.craftlabs</groupId>
|
||||
<artifactId>craftlabs-auth-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package cn.craftlabs.auth.bitanswer;
|
||||
|
||||
import cn.craftlabs.auth.AuthProvider;
|
||||
import cn.craftlabs.auth.AuthResult;
|
||||
import cn.craftlabs.auth.LicenseInfo;
|
||||
import cn.craftlabs.auth.internal.NativeBridge;
|
||||
|
||||
/**
|
||||
* 比特安索(Bitanswer)授权提供者的 Java 封装。
|
||||
*
|
||||
* <p>在静态初始化块中加载本地库 {@code craftlabs_auth_bitanswer},通过 {@link
|
||||
* cn.craftlabs.auth.internal.NativeBridge} 将 {@link cn.craftlabs.auth.AuthProvider} 各方法委托给 C
|
||||
* 端实现。重复调用 {@link #initialize(String)} 会先销毁已有 native 句柄再重新初始化。
|
||||
*
|
||||
* <p>版权所有 © 广州创飞人工智能技术有限公司
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
public final class BitAnswerProvider implements AuthProvider {
|
||||
static {
|
||||
System.loadLibrary("craftlabs_auth_bitanswer");
|
||||
}
|
||||
|
||||
private long nativeHandle;
|
||||
|
||||
@Override
|
||||
public AuthResult initialize(String configJson) {
|
||||
if (nativeHandle != 0L) {
|
||||
NativeBridge.nativeDestroy(nativeHandle);
|
||||
nativeHandle = 0L;
|
||||
}
|
||||
nativeHandle = NativeBridge.nativeInitialize(configJson != null ? configJson : "{}");
|
||||
return new AuthResult(true, "Initialized");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResult activate(String licenseKey) {
|
||||
return NativeBridge.nativeActivate(nativeHandle, licenseKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResult checkLicense() {
|
||||
return NativeBridge.nativeCheckLicense(nativeHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LicenseInfo getLicenseInfo() {
|
||||
return NativeBridge.nativeGetLicenseInfo(nativeHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFeature(String featureName) {
|
||||
return NativeBridge.nativeHasFeature(nativeHandle, featureName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResult release() {
|
||||
return NativeBridge.nativeRelease(nativeHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResult heartbeat() {
|
||||
return NativeBridge.nativeHeartbeat(nativeHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (nativeHandle != 0L) {
|
||||
NativeBridge.nativeDestroy(nativeHandle);
|
||||
nativeHandle = 0L;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.craftlabs</groupId>
|
||||
<artifactId>craftlabs-auth-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>craftlabs-auth-core</artifactId>
|
||||
<name>CraftLabs Auth — core API</name>
|
||||
<packaging>jar</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1,37 @@
|
||||
package cn.craftlabs.auth;
|
||||
|
||||
/**
|
||||
* 授权能力的统一契约:初始化、激活、校验许可、查询特性与释放等生命周期方法。
|
||||
*
|
||||
* <p>实现类负责加载对应 native 或远端适配器;调用方应在不再使用时调用 {@link #close()} 释放底层资源。
|
||||
*
|
||||
* <p>版权所有 © 广州创飞人工智能技术有限公司
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
public interface AuthProvider extends AutoCloseable {
|
||||
/** 使用 JSON 配置初始化授权上下文;可重复调用,实现类应妥善处理句柄重置。 */
|
||||
AuthResult initialize(String configJson);
|
||||
|
||||
/** 使用许可密钥激活(具体语义由底层供应商决定)。 */
|
||||
AuthResult activate(String licenseKey);
|
||||
|
||||
/** 校验当前许可是否有效。 */
|
||||
AuthResult checkLicense();
|
||||
|
||||
/** 返回当前许可详情;具体字段含义与失败时的表现以各 {@link AuthProvider} 实现为准。 */
|
||||
LicenseInfo getLicenseInfo();
|
||||
|
||||
/** 查询指定特性是否开启。 */
|
||||
boolean hasFeature(String featureName);
|
||||
|
||||
/** 释放/注销当前许可占用(与 {@link #close()} 侧重点不同,依供应商语义)。 */
|
||||
AuthResult release();
|
||||
|
||||
/** 会话心跳,用于在线校验或租约续期等场景。 */
|
||||
AuthResult heartbeat();
|
||||
|
||||
/** 释放 native 或远端资源;接口关闭后不得再调用其他方法。 */
|
||||
@Override
|
||||
void close();
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package cn.craftlabs.auth;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 单次授权操作的结果:成功与否及 UTF-8 说明信息(可能来自 native,勿假定固定文案)。
|
||||
*
|
||||
* <p>版权所有 © 广州创飞人工智能技术有限公司
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
public final class AuthResult {
|
||||
private final boolean success;
|
||||
private final String message;
|
||||
|
||||
public AuthResult(boolean success, String message) {
|
||||
this.success = success;
|
||||
this.message = message != null ? message : "";
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
AuthResult that = (AuthResult) o;
|
||||
return success == that.success && Objects.equals(message, that.message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(success, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AuthResult{success=" + success + ", message='" + message + '\'' + '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package cn.craftlabs.auth;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 当前许可快照:是否已授权、过期时间及特性开关映射(不可变视图)。
|
||||
*
|
||||
* <p>版权所有 © 广州创飞人工智能技术有限公司
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
public final class LicenseInfo {
|
||||
private final boolean licensed;
|
||||
private final Date expirationDate;
|
||||
private final Map<String, Boolean> features;
|
||||
|
||||
public LicenseInfo(boolean licensed, Date expirationDate, Map<String, Boolean> features) {
|
||||
this.licensed = licensed;
|
||||
this.expirationDate = expirationDate;
|
||||
this.features =
|
||||
features == null ? Collections.emptyMap() : Collections.unmodifiableMap(features);
|
||||
}
|
||||
|
||||
public boolean isLicensed() {
|
||||
return licensed;
|
||||
}
|
||||
|
||||
public Date getExpirationDate() {
|
||||
return expirationDate;
|
||||
}
|
||||
|
||||
public Map<String, Boolean> getFeatures() {
|
||||
return features;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
LicenseInfo that = (LicenseInfo) o;
|
||||
return licensed == that.licensed
|
||||
&& Objects.equals(expirationDate, that.expirationDate)
|
||||
&& Objects.equals(features, that.features);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(licensed, expirationDate, features);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LicenseInfo{licensed="
|
||||
+ licensed
|
||||
+ ", expirationDate="
|
||||
+ expirationDate
|
||||
+ ", features="
|
||||
+ features
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.craftlabs.auth.internal;
|
||||
|
||||
import cn.craftlabs.auth.AuthResult;
|
||||
import cn.craftlabs.auth.LicenseInfo;
|
||||
|
||||
/**
|
||||
* JNI 入口:与 {@code jni_bridge.cpp} 中的 {@code Java_cn_craftlabs_auth_internal_NativeBridge_*}
|
||||
* 函数签名一一对应,由各 {@code AuthProvider} 实现所在的模块加载同名 native 库后使用。
|
||||
*
|
||||
* <p>版权所有 © 广州创飞人工智能技术有限公司
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
public final class NativeBridge {
|
||||
private NativeBridge() {}
|
||||
|
||||
public static native long nativeInitialize(String configJson);
|
||||
|
||||
public static native void nativeDestroy(long handle);
|
||||
|
||||
public static native AuthResult nativeActivate(long handle, String licenseKey);
|
||||
|
||||
public static native AuthResult nativeCheckLicense(long handle);
|
||||
|
||||
public static native LicenseInfo nativeGetLicenseInfo(long handle);
|
||||
|
||||
public static native boolean nativeHasFeature(long handle, String featureName);
|
||||
|
||||
public static native AuthResult nativeRelease(long handle);
|
||||
|
||||
public static native AuthResult nativeHeartbeat(long handle);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.craftlabs</groupId>
|
||||
<artifactId>craftlabs-auth-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>craftlabs-auth-selfhosted</artifactId>
|
||||
<name>CraftLabs Auth — self-hosted HTTP adapter</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.craftlabs</groupId>
|
||||
<artifactId>craftlabs-auth-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package cn.craftlabs.auth.selfhosted;
|
||||
|
||||
import cn.craftlabs.auth.AuthProvider;
|
||||
import cn.craftlabs.auth.AuthResult;
|
||||
import cn.craftlabs.auth.LicenseInfo;
|
||||
import cn.craftlabs.auth.internal.NativeBridge;
|
||||
|
||||
/**
|
||||
* 自研授权(HTTP)适配器的 Java 封装。
|
||||
*
|
||||
* <p>当前阶段复用与 Bitanswer 相同的 native 桩实现;后续可切换为独立 {@code
|
||||
* libcraftlabs_auth_selfhosted}。
|
||||
*
|
||||
* <p>版权所有 © 广州创飞人工智能技术有限公司
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
public final class SelfHostedAuthProvider implements AuthProvider {
|
||||
static {
|
||||
System.loadLibrary("craftlabs_auth_bitanswer");
|
||||
}
|
||||
|
||||
private long nativeHandle;
|
||||
|
||||
@Override
|
||||
public AuthResult initialize(String configJson) {
|
||||
if (nativeHandle != 0L) {
|
||||
NativeBridge.nativeDestroy(nativeHandle);
|
||||
nativeHandle = 0L;
|
||||
}
|
||||
nativeHandle = NativeBridge.nativeInitialize(configJson != null ? configJson : "{}");
|
||||
return new AuthResult(true, "Initialized (self-hosted stub)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResult activate(String licenseKey) {
|
||||
return NativeBridge.nativeActivate(nativeHandle, licenseKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResult checkLicense() {
|
||||
return NativeBridge.nativeCheckLicense(nativeHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LicenseInfo getLicenseInfo() {
|
||||
return NativeBridge.nativeGetLicenseInfo(nativeHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFeature(String featureName) {
|
||||
return NativeBridge.nativeHasFeature(nativeHandle, featureName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResult release() {
|
||||
return NativeBridge.nativeRelease(nativeHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResult heartbeat() {
|
||||
return NativeBridge.nativeHeartbeat(nativeHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (nativeHandle != 0L) {
|
||||
NativeBridge.nativeDestroy(nativeHandle);
|
||||
nativeHandle = 0L;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.craftlabs</groupId>
|
||||
<artifactId>craftlabs-auth-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>craftlabs-auth-tests</artifactId>
|
||||
<name>CraftLabs Auth — integration tests</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.craftlabs</groupId>
|
||||
<artifactId>craftlabs-auth-bitanswer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<native.library.path>${project.basedir}/../../native/build</native.library.path>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>-Djava.library.path=${native.library.path}</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,30 @@
|
||||
package cn.craftlabs.auth;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import cn.craftlabs.auth.bitanswer.BitAnswerProvider;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* {@link BitAnswerProvider} 集成测试(依赖 native 桩)。
|
||||
*
|
||||
* <p>版权所有 © 广州创飞人工智能技术有限公司
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
class BitAnswerProviderTest {
|
||||
|
||||
@Test
|
||||
void initializeCheckAndLicenseInfo_roundTrip() {
|
||||
try (AuthProvider p = new BitAnswerProvider()) {
|
||||
AuthResult init = p.initialize("{}");
|
||||
assertTrue(init.isSuccess(), init.getMessage());
|
||||
AuthResult ok = p.checkLicense();
|
||||
assertTrue(ok.isSuccess(), ok.getMessage());
|
||||
LicenseInfo info = p.getLicenseInfo();
|
||||
assertNotNull(info);
|
||||
assertTrue(info.isLicensed());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>cn.craftlabs</groupId>
|
||||
<artifactId>craftlabs-auth-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>CraftLabs Auth SDK (parent)</name>
|
||||
|
||||
<modules>
|
||||
<module>craftlabs-auth-core</module>
|
||||
<module>craftlabs-auth-bitanswer</module>
|
||||
<module>craftlabs-auth-selfhosted</module>
|
||||
<module>craftlabs-auth-tests</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.release>17</maven.compiler.release>
|
||||
<junit.version>5.10.2</junit.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.craftlabs</groupId>
|
||||
<artifactId>craftlabs-auth-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.2.5</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,58 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(craftlabs_auth_bitanswer LANGUAGES C CXX)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CRAFTLABS_AUTH_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
option(CRAFTLABS_BUILD_JNI "Build JNI bridge (requires JDK)" ON)
|
||||
option(CRAFTLABS_BUILD_TESTS "Build native smoke tests" ON)
|
||||
|
||||
set(CRAFTLABS_AUTH_CORE_SOURCES
|
||||
"${CRAFTLABS_AUTH_SRC_DIR}/src/craftlabs_auth.cpp"
|
||||
"${CRAFTLABS_AUTH_SRC_DIR}/src/bitanswer/bitanswer_adapter.cpp"
|
||||
"${CRAFTLABS_AUTH_SRC_DIR}/src/selfhosted/http_client.cpp"
|
||||
"${CRAFTLABS_AUTH_SRC_DIR}/src/selfhosted/selfhosted_adapter.cpp"
|
||||
)
|
||||
|
||||
if(CRAFTLABS_BUILD_JNI)
|
||||
find_package(JNI REQUIRED)
|
||||
list(APPEND CRAFTLABS_AUTH_CORE_SOURCES
|
||||
"${CRAFTLABS_AUTH_SRC_DIR}/src/jni/jni_bridge.cpp")
|
||||
endif()
|
||||
|
||||
add_library(craftlabs_auth_bitanswer SHARED ${CRAFTLABS_AUTH_CORE_SOURCES})
|
||||
|
||||
target_include_directories(craftlabs_auth_bitanswer
|
||||
PUBLIC
|
||||
"${CRAFTLABS_AUTH_SRC_DIR}/include"
|
||||
PRIVATE
|
||||
"${CRAFTLABS_AUTH_SRC_DIR}/src"
|
||||
)
|
||||
|
||||
if(CRAFTLABS_BUILD_JNI)
|
||||
target_include_directories(craftlabs_auth_bitanswer PRIVATE ${JNI_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(craftlabs_auth_bitanswer PRIVATE CRAFTLABS_AUTH_PLATFORM_WINDOWS=1)
|
||||
elseif(APPLE)
|
||||
target_compile_definitions(craftlabs_auth_bitanswer PRIVATE CRAFTLABS_AUTH_PLATFORM_MACOS=1)
|
||||
else()
|
||||
target_compile_definitions(craftlabs_auth_bitanswer PRIVATE CRAFTLABS_AUTH_PLATFORM_LINUX=1)
|
||||
endif()
|
||||
|
||||
if(CRAFTLABS_BUILD_TESTS)
|
||||
enable_testing()
|
||||
add_executable(craftlabs_auth_smoke
|
||||
"${CRAFTLABS_AUTH_SRC_DIR}/tests/smoke_test.cpp")
|
||||
target_link_libraries(craftlabs_auth_smoke PRIVATE craftlabs_auth_bitanswer)
|
||||
target_include_directories(craftlabs_auth_smoke PRIVATE
|
||||
"${CRAFTLABS_AUTH_SRC_DIR}/include")
|
||||
set_target_properties(craftlabs_auth_smoke PROPERTIES
|
||||
BUILD_RPATH "$<TARGET_FILE_DIR:craftlabs_auth_bitanswer>")
|
||||
add_test(NAME craftlabs_auth_smoke COMMAND craftlabs_auth_smoke)
|
||||
endif()
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* CraftLabs 授权 SDK — C 语言 FFI 公共头文件。
|
||||
*
|
||||
* 版权所有 © 广州创飞人工智能技术有限公司
|
||||
* 开发者:huangping@craftlabs.cn
|
||||
*/
|
||||
#ifndef CRAFTLABS_AUTH_H
|
||||
#define CRAFTLABS_AUTH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* FFI / Python(ctypes、cffi)说明
|
||||
* ----------------------------------
|
||||
* - 所有 `const char*` 均为 **UTF-8** 编码、以 `\0` 结尾。
|
||||
* - `AuthHandle`:不透明指针,仅由本库函数产生与销毁(`auth_initialize` / `auth_destroy`)。
|
||||
* - `AuthResult`、`LicenseInfo` 使用 `stdint` 定宽字段,避免 `time_t`/`int` 宽度随平台变化导致 Python 侧 Structure 布局错误。
|
||||
* - `AuthResult.message`:指向 **由本库管理的静态或内部只读缓冲区**,调用方不得 `free`;在任意后续对本库的再次调用之后视为可能失效(与其它 FFI 语言惯例一致)。
|
||||
* - `auth_get_license_info` 返回的 `LicenseInfo*`(及其中 `feature_names` / `feature_values` 指向的数组)须通过 `auth_free_license_info` 释放;释放后不得再读指针成员。
|
||||
* - 官方 Python 绑定见仓库 `python/craftlabs_auth/`(ctypes,与本头文件字段一一对应)。
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#define CRAFTLABS_API __declspec(dllexport)
|
||||
#else
|
||||
#define CRAFTLABS_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void* AuthHandle;
|
||||
|
||||
typedef struct {
|
||||
int32_t success; /* 1: 成功, 0: 失败 */
|
||||
const char* message; /* UTF-8,由库持有,勿 free */
|
||||
} AuthResult;
|
||||
|
||||
typedef struct {
|
||||
int32_t is_licensed; /* 1: 已授权, 0: 否 */
|
||||
int64_t expiration_date; /* Unix 纪元秒数(UTC),0 表示无过期限制 */
|
||||
const char** feature_names; /* 以 NULL 结尾的指针数组,或长度由 feature_count 给出,由随 LicenseInfo 一并释放 */
|
||||
int32_t* feature_values; /* 与 feature_names 一一对应,元素为 0/1 */
|
||||
int32_t feature_count;
|
||||
} LicenseInfo;
|
||||
|
||||
CRAFTLABS_API AuthHandle auth_initialize(const char* config_json);
|
||||
|
||||
CRAFTLABS_API AuthResult auth_activate(AuthHandle handle, const char* license_key);
|
||||
|
||||
CRAFTLABS_API AuthResult auth_check_license(AuthHandle handle);
|
||||
|
||||
CRAFTLABS_API LicenseInfo* auth_get_license_info(AuthHandle handle);
|
||||
|
||||
CRAFTLABS_API void auth_free_license_info(LicenseInfo* info);
|
||||
|
||||
CRAFTLABS_API int32_t auth_has_feature(AuthHandle handle, const char* feature_name);
|
||||
|
||||
CRAFTLABS_API AuthResult auth_release(AuthHandle handle);
|
||||
|
||||
CRAFTLABS_API AuthResult auth_heartbeat(AuthHandle handle);
|
||||
|
||||
CRAFTLABS_API void auth_destroy(AuthHandle handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 比特安索(Bitanswer)适配器实现(占位)。
|
||||
*
|
||||
* 版权所有 © 广州创飞人工智能技术有限公司
|
||||
* 开发者:huangping@craftlabs.cn
|
||||
*/
|
||||
#include "bitanswer_adapter.h"
|
||||
|
||||
void bitanswer_adapter_register(void) {
|
||||
/* 后续里程碑:在此挂接 Bit_LoginEx、Bit_QueryFeature 等与 craftlabs_auth 生命周期对齐。 */
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 比特安索(Bitanswer)适配器注册入口。
|
||||
*
|
||||
* 版权所有 © 广州创飞人工智能技术有限公司
|
||||
* 开发者:huangping@craftlabs.cn
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 向核心库注册 Bitanswer 相关钩子;当前里程碑可为空实现,后续接入 Bit_LoginEx / Bit_QueryFeature 等。
|
||||
*/
|
||||
void bitanswer_adapter_register(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* CraftLabs 授权 SDK — 核心 C API 实现(含桩逻辑与各适配器注册)。
|
||||
*
|
||||
* 版权所有 © 广州创飞人工智能技术有限公司
|
||||
* 开发者:huangping@craftlabs.cn
|
||||
*/
|
||||
#include "craftlabs_auth.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "bitanswer/bitanswer_adapter.h"
|
||||
#include "selfhosted/selfhosted_adapter.h"
|
||||
|
||||
namespace {
|
||||
|
||||
/** 不透明句柄对应的内部状态;后续可扩展为供应商特定字段。 */
|
||||
struct AuthContext {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
static const AuthResult k_ok = {1, "stub"};
|
||||
static const AuthResult k_fail = {0, "stub failure"};
|
||||
|
||||
AuthContext* as_ctx(AuthHandle h) {
|
||||
return reinterpret_cast<AuthContext*>(h);
|
||||
}
|
||||
|
||||
void ensure_adapters_registered_once() {
|
||||
static bool once = false;
|
||||
if (!once) {
|
||||
bitanswer_adapter_register();
|
||||
selfhosted_adapter_register();
|
||||
once = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
CRAFTLABS_API AuthHandle auth_initialize(const char* /* config_json */) {
|
||||
ensure_adapters_registered_once();
|
||||
auto* ctx = new AuthContext{};
|
||||
ctx->dummy = 1;
|
||||
return reinterpret_cast<AuthHandle>(ctx);
|
||||
}
|
||||
|
||||
CRAFTLABS_API AuthResult auth_activate(AuthHandle handle, const char* /* license_key */) {
|
||||
if (!handle) {
|
||||
return k_fail;
|
||||
}
|
||||
(void)as_ctx(handle);
|
||||
return k_ok;
|
||||
}
|
||||
|
||||
CRAFTLABS_API AuthResult auth_check_license(AuthHandle handle) {
|
||||
if (!handle) {
|
||||
return k_fail;
|
||||
}
|
||||
return k_ok;
|
||||
}
|
||||
|
||||
CRAFTLABS_API LicenseInfo* auth_get_license_info(AuthHandle handle) {
|
||||
if (!handle) {
|
||||
return nullptr;
|
||||
}
|
||||
auto* info = static_cast<LicenseInfo*>(std::malloc(sizeof(LicenseInfo)));
|
||||
if (!info) {
|
||||
return nullptr;
|
||||
}
|
||||
info->is_licensed = 1;
|
||||
info->expiration_date = 0;
|
||||
info->feature_names = nullptr;
|
||||
info->feature_values = nullptr;
|
||||
info->feature_count = 0;
|
||||
return info;
|
||||
}
|
||||
|
||||
CRAFTLABS_API void auth_free_license_info(LicenseInfo* info) {
|
||||
std::free(info);
|
||||
}
|
||||
|
||||
CRAFTLABS_API int32_t auth_has_feature(AuthHandle handle, const char* /* feature_name */) {
|
||||
if (!handle) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
CRAFTLABS_API AuthResult auth_release(AuthHandle handle) {
|
||||
if (!handle) {
|
||||
return k_fail;
|
||||
}
|
||||
return k_ok;
|
||||
}
|
||||
|
||||
CRAFTLABS_API AuthResult auth_heartbeat(AuthHandle handle) {
|
||||
if (!handle) {
|
||||
return k_fail;
|
||||
}
|
||||
return k_ok;
|
||||
}
|
||||
|
||||
CRAFTLABS_API void auth_destroy(AuthHandle handle) {
|
||||
if (!handle) {
|
||||
return;
|
||||
}
|
||||
delete as_ctx(handle);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* JNI 桥:java 包 cn.craftlabs.auth.internal.NativeBridge 与 craftlabs_auth.h C API 之间的映射。
|
||||
*
|
||||
* 版权所有 © 广州创飞人工智能技术有限公司
|
||||
* 开发者:huangping@craftlabs.cn
|
||||
*/
|
||||
#include <cstdint>
|
||||
#include <jni.h>
|
||||
|
||||
#include "craftlabs_auth.h"
|
||||
|
||||
namespace {
|
||||
|
||||
AuthHandle from_jlong(jlong ptr) {
|
||||
return reinterpret_cast<AuthHandle>(static_cast<uintptr_t>(ptr));
|
||||
}
|
||||
|
||||
jobject make_auth_result(JNIEnv* env, const AuthResult& r) {
|
||||
jclass cls = env->FindClass("cn/craftlabs/auth/AuthResult");
|
||||
if (!cls) {
|
||||
return nullptr;
|
||||
}
|
||||
jmethodID ctor = env->GetMethodID(cls, "<init>", "(ZLjava/lang/String;)V");
|
||||
if (!ctor) {
|
||||
return nullptr;
|
||||
}
|
||||
jboolean ok = (r.success != 0) ? JNI_TRUE : JNI_FALSE;
|
||||
jstring msg = env->NewStringUTF(r.message ? r.message : "");
|
||||
if (!msg) {
|
||||
return nullptr;
|
||||
}
|
||||
jobject out = env->NewObject(cls, ctor, ok, msg);
|
||||
env->DeleteLocalRef(msg);
|
||||
return out;
|
||||
}
|
||||
|
||||
jobject make_license_info(JNIEnv* env, LicenseInfo* info) {
|
||||
if (!info) {
|
||||
return nullptr;
|
||||
}
|
||||
jclass cls = env->FindClass("cn/craftlabs/auth/LicenseInfo");
|
||||
if (!cls) {
|
||||
return nullptr;
|
||||
}
|
||||
jmethodID ctor = env->GetMethodID(cls, "<init>", "(ZLjava/util/Date;Ljava/util/Map;)V");
|
||||
if (!ctor) {
|
||||
return nullptr;
|
||||
}
|
||||
jboolean licensed = info->is_licensed ? JNI_TRUE : JNI_FALSE;
|
||||
|
||||
jobject date = nullptr;
|
||||
if (info->expiration_date != 0) {
|
||||
jclass dateCls = env->FindClass("java/util/Date");
|
||||
jmethodID dateCtor = env->GetMethodID(dateCls, "<init>", "(J)V");
|
||||
jlong ms = static_cast<jlong>(info->expiration_date) * 1000LL;
|
||||
date = env->NewObject(dateCls, dateCtor, ms);
|
||||
}
|
||||
|
||||
jclass mapCls = env->FindClass("java/util/HashMap");
|
||||
jmethodID mapCtor = env->GetMethodID(mapCls, "<init>", "()V");
|
||||
jobject map = env->NewObject(mapCls, mapCtor);
|
||||
jmethodID put = env->GetMethodID(mapCls, "put",
|
||||
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
for (int i = 0; i < info->feature_count; ++i) {
|
||||
const char* name = info->feature_names[i];
|
||||
int v = info->feature_values[i];
|
||||
jstring jn = env->NewStringUTF(name ? name : "");
|
||||
jclass boolCls = env->FindClass("java/lang/Boolean");
|
||||
jmethodID valueOf =
|
||||
env->GetStaticMethodID(boolCls, "valueOf", "(Z)Ljava/lang/Boolean;");
|
||||
jobject jb = env->CallStaticObjectMethod(boolCls, valueOf, v ? JNI_TRUE : JNI_FALSE);
|
||||
env->CallObjectMethod(map, put, jn, jb);
|
||||
env->DeleteLocalRef(jn);
|
||||
env->DeleteLocalRef(jb);
|
||||
}
|
||||
jobject out = env->NewObject(cls, ctor, licensed, date, map);
|
||||
if (date) {
|
||||
env->DeleteLocalRef(date);
|
||||
}
|
||||
env->DeleteLocalRef(map);
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_cn_craftlabs_auth_internal_NativeBridge_nativeInitialize(
|
||||
JNIEnv* env, jclass, jstring configJson) {
|
||||
const char* utf = configJson ? env->GetStringUTFChars(configJson, nullptr) : nullptr;
|
||||
AuthHandle h = auth_initialize(utf ? utf : "{}");
|
||||
if (configJson && utf) {
|
||||
env->ReleaseStringUTFChars(configJson, utf);
|
||||
}
|
||||
return static_cast<jlong>(reinterpret_cast<uintptr_t>(h));
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_cn_craftlabs_auth_internal_NativeBridge_nativeDestroy(JNIEnv*,
|
||||
jclass,
|
||||
jlong handle) {
|
||||
auth_destroy(from_jlong(handle));
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_cn_craftlabs_auth_internal_NativeBridge_nativeActivate(
|
||||
JNIEnv* env, jclass, jlong handle, jstring licenseKey) {
|
||||
const char* utf = licenseKey ? env->GetStringUTFChars(licenseKey, nullptr) : "";
|
||||
AuthResult r = auth_activate(from_jlong(handle), utf ? utf : "");
|
||||
if (licenseKey && utf) {
|
||||
env->ReleaseStringUTFChars(licenseKey, utf);
|
||||
}
|
||||
return make_auth_result(env, r);
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_cn_craftlabs_auth_internal_NativeBridge_nativeCheckLicense(
|
||||
JNIEnv* env, jclass, jlong handle) {
|
||||
AuthResult r = auth_check_license(from_jlong(handle));
|
||||
return make_auth_result(env, r);
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_cn_craftlabs_auth_internal_NativeBridge_nativeGetLicenseInfo(
|
||||
JNIEnv* env, jclass, jlong handle) {
|
||||
LicenseInfo* info = auth_get_license_info(from_jlong(handle));
|
||||
jobject jinfo = make_license_info(env, info);
|
||||
auth_free_license_info(info);
|
||||
return jinfo;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_cn_craftlabs_auth_internal_NativeBridge_nativeHasFeature(
|
||||
JNIEnv* env, jclass, jlong handle, jstring featureName) {
|
||||
const char* utf = featureName ? env->GetStringUTFChars(featureName, nullptr) : "";
|
||||
int v = auth_has_feature(from_jlong(handle), utf ? utf : "");
|
||||
if (featureName && utf) {
|
||||
env->ReleaseStringUTFChars(featureName, utf);
|
||||
}
|
||||
return v ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_cn_craftlabs_auth_internal_NativeBridge_nativeRelease(JNIEnv* env,
|
||||
jclass,
|
||||
jlong handle) {
|
||||
AuthResult r = auth_release(from_jlong(handle));
|
||||
return make_auth_result(env, r);
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_cn_craftlabs_auth_internal_NativeBridge_nativeHeartbeat(
|
||||
JNIEnv* env, jclass, jlong handle) {
|
||||
AuthResult r = auth_heartbeat(from_jlong(handle));
|
||||
return make_auth_result(env, r);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* 自研适配器 HTTP 客户端桩实现。
|
||||
*
|
||||
* 版权所有 © 广州创飞人工智能技术有限公司
|
||||
* 开发者:huangping@craftlabs.cn
|
||||
*/
|
||||
#include "http_client.h"
|
||||
|
||||
int selfhosted_http_ping(const char* /* base_url */) {
|
||||
/* 接入 libcurl 等之后再实现真实请求;当前保证注册阶段可链接通过。 */
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 自研适配器用的最小 HTTP 门面(后续可接 libcurl / WinHTTP)。
|
||||
*
|
||||
* 版权所有 © 广州创飞人工智能技术有限公司
|
||||
* 开发者:huangping@craftlabs.cn
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 对给定基地址做连通性探测;当前为占位实现。
|
||||
* @param base_url 服务根 URL,可为空(实现定义行为)。
|
||||
* @return 0 表示占位成功,非 0 预留为错误码。
|
||||
*/
|
||||
int selfhosted_http_ping(const char* base_url);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* 自研 HTTP 授权适配器实现。
|
||||
*
|
||||
* 版权所有 © 广州创飞人工智能技术有限公司
|
||||
* 开发者:huangping@craftlabs.cn
|
||||
*/
|
||||
#include "selfhosted_adapter.h"
|
||||
#include "http_client.h"
|
||||
|
||||
void selfhosted_adapter_register(void) {
|
||||
(void)selfhosted_http_ping("");
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 自研 HTTP 授权适配器 — 注册入口。
|
||||
*
|
||||
* 版权所有 © 广州创飞人工智能技术有限公司
|
||||
* 开发者:huangping@craftlabs.cn
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** 注册自研适配器依赖(如 HTTP 客户端探测);可与 Bitanswer 注册并存。 */
|
||||
void selfhosted_adapter_register(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Native 库冒烟测试。
|
||||
*
|
||||
* 版权所有 © 广州创飞人工智能技术有限公司
|
||||
* 开发者:huangping@craftlabs.cn
|
||||
*/
|
||||
#include "craftlabs_auth.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
int main() {
|
||||
AuthHandle h = auth_initialize("{}");
|
||||
if (!h) {
|
||||
std::fprintf(stderr, "auth_initialize returned null\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
AuthResult r = auth_check_license(h);
|
||||
if (r.success == 0) {
|
||||
std::fprintf(stderr, "auth_check_license failed\n");
|
||||
auth_destroy(h);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
LicenseInfo* info = auth_get_license_info(h);
|
||||
if (!info) {
|
||||
std::fprintf(stderr, "auth_get_license_info returned null\n");
|
||||
auth_destroy(h);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auth_free_license_info(info);
|
||||
auth_destroy(h);
|
||||
std::printf("native smoke ok\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user