mirror of
https://github.com/hpd840321/craftlabs-authorization-sdk.git
synced 2026-06-09 01:50:30 +08:00
feat(sdk): AuthConfigs, JSON Schema, examples, and release checksum CI
Add craftlabs-auth-config.schema.json, Java AuthConfigs model with tests, example configs aligned to BP-10, C/Java/auth-config documentation, native header notes, RELEASING guide, and workflow to verify SDK artifact checksums on release tags. Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
# 手动触发:打包 SDK + Native(.so) 并生成 SHA256SUMS,供 GitHub Release 上传
|
||||
name: sdk-release-checksums
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
checksums:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "17"
|
||||
cache: maven
|
||||
- name: Install native build deps
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential cmake
|
||||
- name: Build native (.so)
|
||||
run: |
|
||||
cmake -S native -B native/build -DCMAKE_BUILD_TYPE=Release -DCRAFTLABS_BUILD_JNI=ON
|
||||
cmake --build native/build --parallel
|
||||
- name: Maven package (SDK jars)
|
||||
run: mvn -f java/pom.xml -B -DskipTests package
|
||||
- name: Generate SHA256SUMS
|
||||
run: |
|
||||
chmod +x scripts/sdk-release-checksums.sh
|
||||
./scripts/sdk-release-checksums.sh --no-mvn --output dist/sdk-release --native-path "${{ github.workspace }}/native/build"
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdk-release-${{ github.ref_name }}
|
||||
path: |
|
||||
dist/sdk-release/
|
||||
java/craftlabs-auth-core/target/*.jar
|
||||
java/craftlabs-auth-bitanswer/target/*.jar
|
||||
java/craftlabs-auth-selfhosted/target/*.jar
|
||||
@@ -0,0 +1,35 @@
|
||||
# `initialize(config_json)` 配置说明
|
||||
|
||||
`AuthProvider.initialize(String)` 与 C API `auth_initialize(const char* config_json)` 共用同一 JSON 语义,版本由 **`schemaVersion: 1`** 锁定。
|
||||
|
||||
## 规范与示例
|
||||
|
||||
| 资源 | 路径 |
|
||||
|------|------|
|
||||
| JSON Schema | `schemas/craftlabs-auth-config.schema.json` |
|
||||
| 码头 / 集团拓扑示例 | `examples/config/wharf.bitanswer.json` |
|
||||
| 学校 / 边设备示例 | `examples/config/school.bitanswer.json` |
|
||||
| 流动人口 / 项目示例 | `examples/config/floating.bitanswer.json` |
|
||||
| 学校 / 自研 HTTP 示例 | `examples/config/school.selfhosted.json` |
|
||||
|
||||
## Java 解析与校验
|
||||
|
||||
```java
|
||||
import cn.craftlabs.auth.config.AuthConfig;
|
||||
import cn.craftlabs.auth.config.AuthConfigException;
|
||||
import cn.craftlabs.auth.config.AuthConfigs;
|
||||
|
||||
AuthConfig cfg = AuthConfigs.parse(jsonString);
|
||||
// 再交给实现(与校验使用同一字符串即可)
|
||||
provider.initialize(jsonString);
|
||||
```
|
||||
|
||||
`AuthConfig` 提供 `bitanswerFeatureId(String logicalKey)` 等辅助方法,供后续在 `hasFeature` 与比特 `QueryFeature` 之间做映射。
|
||||
|
||||
## 场景字段摘要
|
||||
|
||||
- **wharf**:`wharf.topology`(`cloud` / `group` / `local_float`)等与集中授权拓扑相关的**提示**;实际连网方式仍以 `bitanswer.url` 为准。
|
||||
- **school**:`school.edgeDeviceId` 等用于运营对账;是否写入比特自定义字段由实现阶段决定。
|
||||
- **floating**:**必填** `floating.projectId`;表达「按项目」授权锚点,与商务合同、控制台业务模板需一致。
|
||||
|
||||
后续优化(错误码、OIDC、集团占点策略等)在保持 `schemaVersion` 或递增版本的前提下扩展字段即可。
|
||||
@@ -1,12 +1,11 @@
|
||||
# 比特授权云 · C 语言接口定义(离线摘录)
|
||||
|
||||
> 本文档由官网页面离线摘录并整理排版,便于本地检索。官方地址:<https://doc.bitanswer.cn/docs/client-api/c-interface-definitions-v2/>
|
||||
> 本文档由官网页面离线摘录并整理排版,便于本地检索。官方地址:[https://doc.bitanswer.cn/docs/client-api/c-interface-definitions-v2/](https://doc.bitanswer.cn/docs/client-api/c-interface-definitions-v2/)
|
||||
|
||||
---
|
||||
|
||||
## 认证
|
||||
|
||||
|
||||
### Bit_Login / Bit_LoginEx
|
||||
|
||||
```c
|
||||
@@ -26,6 +25,7 @@ BIT_STATUS Bit_LoginEx(
|
||||
BIT_HANDLE *pHandle,
|
||||
LOGIN_MODE mode);
|
||||
```
|
||||
|
||||
授权登录。初始化运行环境,获取操作句柄。必须在除升级函数之外的其它操作前执行。根据登录模式的不同可能需要连接授权服务器。
|
||||
|
||||
Bit_Login 等价于 Bit_LoginEx(…, featureId=0,szReserved=NULL, …),当需要登录包含指定特征项的授权时才需要调用Bit_LoginEx。
|
||||
@@ -50,6 +50,7 @@ Bit_Login 等价于 Bit_LoginEx(…, featureId=0,szReserved=NULL, …),当
|
||||
lic:///tmp,lic:///data,bit://127.0.0.1:8273
|
||||
/tmp,/data,127.0.0.1:8273 // 等价第1条
|
||||
```
|
||||
|
||||
> 注意:该接口支持通过[配置文件](https://doc.bitanswer.cn/docs/client-api/examples-of-using-the-sdk/#%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6)和[环境变量](https://doc.bitanswer.cn/docs/client-api/examples-of-using-the-sdk/#%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F)来设置该值,如果同时设置优先级为:环境变量 > API传入 > 配置文件。
|
||||
|
||||
- **szSN** - [IN] 授权码(SN)字符串。如果为空(空串或NULL)则尝试寻找所有当前本机可用的SN。
|
||||
@@ -57,10 +58,10 @@ lic:///tmp,lic:///data,bit://127.0.0.1:8273
|
||||
|
||||
| **类型** | **格式** | **说明** |
|
||||
| -------------------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
|
||||
| **授权码** | 比特授权云平台产生的SN 示例:`JNLTGZSE********` | 检查指定SN的License |
|
||||
| **授权码** | 比特授权云平台产生的SN 示例:`JNLTGZSE******`** | 检查指定SN的License |
|
||||
| **BIT-ID(BIT-ID硬件,类似于加密的USB设备)** | 格式:#`<序号>` 或 #bitid:`<序号>` 说明:`<序号>` 为 BIT-ID 的索引号,从 0 开始递增 示例:#0、#1、#`bitid:0、#bitid:1` | 使用BIT-ID授权 |
|
||||
| **激活口令(帐号授权密码或SN激活口令)** | <`xxx`> 通过“<>”包裹起来,中间部分为密码 示例:<1234>, <1233>65447> | 激活口令,是指授权码激活时,需要输入的一种口令,激活后不再需要,目前仅支持浮动授权 使用帐号授权时保存的是帐号授权的密码(已经不推荐),其它授权代表激活口令 |
|
||||
| **既输入SN又输入激活口令** | `xxx<password>`,授权码后边紧跟“<>” 示例:`JNLTGZSE********`<123> | |
|
||||
| **既输入SN又输入激活口令** | `xxx<password>`,授权码后边紧跟“<>” 示例:`JNLTGZSE******`**<123> | |
|
||||
|
||||
|
||||
- **featureId** - [IN] 登录授权所需要包含的特征项ID。
|
||||
@@ -73,6 +74,7 @@ lic:///tmp,lic:///data,bit://127.0.0.1:8273
|
||||
<feature id="" name="" ver=""/>
|
||||
</scope>
|
||||
```
|
||||
|
||||
- **pApplicationData** - [IN] 产品识别码,在Bitanswer SDK头文件里。
|
||||
- **pHandle** - [OUT] 通过Login函数返回的上下文句柄。
|
||||
- **mode** - [IN] 登录模式,按位操作。
|
||||
@@ -154,6 +156,7 @@ BIT_STATUS Bit_LoginByToken(
|
||||
BIT_UCHAR *pApplicationData,
|
||||
BIT_HANDLE *pHandle)
|
||||
```
|
||||
|
||||
帐号授权的登录接口。仅支持两种认证方式,这里是使用比特授权云平台自己产生的access_token进行认证。
|
||||
|
||||
### 参数
|
||||
@@ -182,6 +185,7 @@ BIT_STATUS Bit_LoginByTokenEx(
|
||||
BIT_UCHAR *pApplicationData,
|
||||
BIT_HANDLE *pHandle)
|
||||
```
|
||||
|
||||
帐号授权的登录接口。仅支持两种认证方式,这里是使用OIDC协议产生的id_token认证。
|
||||
|
||||
### 参数
|
||||
@@ -213,6 +217,7 @@ BIT_STATUS Bit_LoginByPassword(
|
||||
BIT_UCHAR *pApplicationData,
|
||||
BIT_HANDLE *pHandle);
|
||||
```
|
||||
|
||||
通过用户名和密码登录帐号授权。
|
||||
|
||||
### 参数
|
||||
@@ -231,6 +236,7 @@ BIT_STATUS Bit_LoginByPassword(
|
||||
BIT_STATUS Bit_Logout (
|
||||
BIT_HANDLE handle)
|
||||
```
|
||||
|
||||
此函数用于释放上下文句柄,退出登录状态,与Login相关接口一一对应。
|
||||
|
||||
### 参数
|
||||
@@ -247,6 +253,7 @@ BIT_STATUS Bit_Revoke (
|
||||
BIT_CHAR *pRevocationInfo,
|
||||
BIT_UINT32 *pRevocationInfoSize)
|
||||
```
|
||||
|
||||
从客户端迁出已激活的浮动授权码。授权码迁出后,可以用于其它的客户端。根据输入参数的不同,本函数可用于在线或离线迁出。
|
||||
|
||||
### 参数
|
||||
@@ -264,6 +271,7 @@ BIT_STATUS Bit_RemoveSn (
|
||||
BIT_PCSTR szSN,
|
||||
BIT_UCHAR *pApplicationData)
|
||||
```
|
||||
|
||||
删除指定授权码在本机的授权数据。
|
||||
|
||||
### 参数
|
||||
@@ -278,6 +286,7 @@ BIT_STATUS Bit_Heartbeat(
|
||||
BIT_HANDLE handle,
|
||||
BIT_UINT32 *pReconnectsNum)
|
||||
```
|
||||
|
||||
手动心跳,可以无限次调用,10s只会触发一次。
|
||||
|
||||
注:当自动心跳停止后,调用该接口可以尝试恢复自动心跳。
|
||||
@@ -298,6 +307,7 @@ BIT_STATUS Bit_SessionControl(
|
||||
BIT_CHAR *pValue,
|
||||
BIT_UINT32 *pValueLen)
|
||||
```
|
||||
|
||||
控制或设置session的信息。具体使用场景可参考《浏览器并发控制》文档。
|
||||
|
||||
### 参数
|
||||
@@ -325,6 +335,7 @@ BIT_STATUS Bit_SetSessionState (
|
||||
BIT_UINT32 state,
|
||||
BIT_VOID *pReserved)
|
||||
```
|
||||
|
||||
设置客户端的状态为空闲状态或繁忙状态或激活状态。
|
||||
|
||||
### 参数
|
||||
@@ -358,7 +369,6 @@ if (用户正在操作) {
|
||||
|
||||
## 激活升级
|
||||
|
||||
|
||||
### Bit_UpdateOnline
|
||||
|
||||
```c
|
||||
@@ -367,6 +377,7 @@ BIT_STATUS Bit_UpdateOnline (
|
||||
BIT_PCSTR szSN,
|
||||
BIT_UCHAR *pApplicationData)
|
||||
```
|
||||
|
||||
此函数用于与授权服务器在线连接,自动完成本地授权的升级操作。本函数需要进行网络连接。
|
||||
|
||||
### 参数
|
||||
@@ -395,6 +406,7 @@ BIT_STATUS Bit_GetRequestInfo (
|
||||
BIT_CHAR *pRequestInfo,
|
||||
BIT_UINT32 *pRequestInfoSize)
|
||||
```
|
||||
|
||||
获取当前运行环境的升级请求码,用于发起本地授权激活及升级请求。如果第一次调用返回错误码260,说明传入的pRequestInfoSize太小,可传入返回的pRequestInfoSize再重新调用一次。
|
||||
|
||||
### 参数
|
||||
@@ -442,6 +454,7 @@ BIT_STATUS Bit_ApplyUpdateInfo(
|
||||
BIT_CHAR *pReceipt,
|
||||
BIT_UINT32 *pReceiptSize)
|
||||
```
|
||||
|
||||
应用升级码完成本地授权激活或升级。本函数必须在获取请求码的同一环境下执行。
|
||||
|
||||
### 参数
|
||||
@@ -475,6 +488,7 @@ BIT_STATUS Bit_ApplyUpdateInfoEx(
|
||||
BIT_CHAR *pReceipt,
|
||||
BIT_UINT32 *pReceiptSize);
|
||||
```
|
||||
|
||||
应用升级码完成远程集团授权激活或升级。一般不建议使用。
|
||||
|
||||
### 参数
|
||||
@@ -495,6 +509,7 @@ BIT_STATUS Bit_GetUpdateInfo (
|
||||
BIT_CHAR *pUpdateInfo,
|
||||
BIT_UINT32 *pUpdateInfoSize)
|
||||
```
|
||||
|
||||
使用请求码与授权服务器进行连接,获取升级码。本函数需要进行网络连接。
|
||||
|
||||
### 参数
|
||||
@@ -508,7 +523,6 @@ BIT_STATUS Bit_GetUpdateInfo (
|
||||
|
||||
## 特征项操作
|
||||
|
||||
|
||||
### Bit_BatchBegin
|
||||
|
||||
```c
|
||||
@@ -516,6 +530,7 @@ BIT_STATUS Bit_BatchBegin(
|
||||
BIT_HANDLE handle,
|
||||
BIT_UINT32 mode)
|
||||
```
|
||||
|
||||
开启批量Query模式,调用此API后调用的所有Query相关API,全部由Bit_BatchEnd接口批量提交连接集团服务。
|
||||
|
||||
### 参数
|
||||
@@ -538,6 +553,7 @@ BIT_STATUS Bit_BatchEnd(
|
||||
BIT_UINT32 *pResultList,
|
||||
BIT_UINT32 *pResultListSize)
|
||||
```
|
||||
|
||||
批量提交Query请求。
|
||||
|
||||
### 参数
|
||||
@@ -577,6 +593,7 @@ BIT_STATUS Bit_QueryFeature (
|
||||
BIT_UINT32 featureId,
|
||||
BIT_UINT32 *pCapacity)
|
||||
```
|
||||
|
||||
开发商可以对软件的某个功能进行单独授权,当程序运行该模块时,可以通过该接口检查是否可用。
|
||||
|
||||
对于单机授权:只检查特征项是否可用。
|
||||
@@ -610,6 +627,7 @@ BIT_STATUS Bit_ReleaseFeature (
|
||||
BIT_UINT32 featureId,
|
||||
BIT_UINT32 *pCapacity)
|
||||
```
|
||||
|
||||
释放所占用的用户数,该函数和Bit_QueryFeature一一对应。
|
||||
|
||||
### 参数
|
||||
@@ -643,6 +661,7 @@ BIT_STATUS Bit_QueryFeatureEx (
|
||||
BIT_UINT32 *pCapacity,
|
||||
BIT_PCSTR xmlScope)
|
||||
```
|
||||
|
||||
集团授权专用,该接口支持占用指定用户数,支持通过特征项版本进行检查。
|
||||
|
||||
### 参数
|
||||
@@ -702,6 +721,7 @@ BIT_STATUS Bit_ReleaseFeatureEx (
|
||||
BIT_UINT32 *pCapacity,
|
||||
BIT_PCSTR xmlScope)
|
||||
```
|
||||
|
||||
集团授权专用,释放指定的用户数。该接口与Bit_QueryFeatureEx对应。
|
||||
|
||||
### 参数
|
||||
@@ -740,6 +760,7 @@ BIT_STATUS Bit_QueryFeatureEx2 (
|
||||
BIT_PCSTR xmlScope,
|
||||
BIT_TICKET *pTicket)
|
||||
```
|
||||
|
||||
可以使用“特征项名称 + 特征项版本”进行用户数占用,支持队列模式。
|
||||
|
||||
对于单机授权:只检查特征项是否可用。
|
||||
@@ -796,6 +817,7 @@ BIT_STATUS Bit_ReleaseFeatureEx2 (
|
||||
BIT_TICKET ticket,
|
||||
BIT_UINT32 consumed)
|
||||
```
|
||||
|
||||
释放ticket所占用的用户数。该函数和Bit_QueryFeatureEx2一一对应。
|
||||
|
||||
### 参数
|
||||
@@ -811,6 +833,7 @@ if (status == BIT_SUCCESS) {
|
||||
// 释放ticket占用的用户数
|
||||
}
|
||||
```
|
||||
|
||||
**特征项Query相关接口比较**
|
||||
|
||||
|
||||
@@ -830,6 +853,7 @@ BIT_STATUS Bit_GetFeatureInfo2 (
|
||||
BIT_PCSTR xmlScope,
|
||||
BIT_INT32 *pExpired)
|
||||
```
|
||||
|
||||
检查特征项是否存在,不会占用授权码或特征项的用户数,获取特征项的剩余有效期。
|
||||
|
||||
### 参数
|
||||
@@ -845,6 +869,7 @@ BIT_STATUS Bit_GetFeatureInfo2 (
|
||||
|
||||
<!-- 或者直接输入:'1.1' -->
|
||||
```
|
||||
|
||||
- **pExpired** - [OUT] 返回该特征项的剩余有效期,正数代表剩余有效期,负数代表过期天数,36500代表永久有效。
|
||||
|
||||
### Bit_GetFeatureInfoEx2
|
||||
@@ -857,6 +882,7 @@ BIT_STATUS Bit_GetFeatureInfoEx2(
|
||||
BIT_CHAR *pFeatureInfo,
|
||||
BIT_UINT32 *pFeatureInfoSize);
|
||||
```
|
||||
|
||||
获取指定feature的信息,以XML格式返回。
|
||||
|
||||
### 参数
|
||||
@@ -872,6 +898,7 @@ BIT_STATUS Bit_GetFeatureInfoEx2(
|
||||
|
||||
<!-- 或者直接输入:'1.1' -->
|
||||
```
|
||||
|
||||
- **pFeatureInfo** - [OUT] feature信息存储区地址。
|
||||
- **pFeatureInfoSize** - [IN/OUT] 会话存储区大小。
|
||||
|
||||
@@ -884,6 +911,7 @@ BIT_STATUS Bit_GetTicketInfo(
|
||||
BIT_CHAR *pXmlInfo,
|
||||
BIT_UINT32 *pSize)
|
||||
```
|
||||
|
||||
获取ticket信息。
|
||||
|
||||
### 参数
|
||||
@@ -946,6 +974,7 @@ BIT_STATUS Bit_ConvertFeature(
|
||||
BIT_UINT32 para4,
|
||||
BIT_UINT32 *pResult);
|
||||
```
|
||||
|
||||
使用“算法”类型的特征项对输入参数进行变换操作,得到唯一对应的4字节结果。
|
||||
|
||||
### 参数
|
||||
@@ -981,6 +1010,7 @@ BIT_STATUS Bit_EncryptFeature(
|
||||
BIT_VOID *pCipherBuffer,
|
||||
BIT_UINT32 dataBufferSize);
|
||||
```
|
||||
|
||||
使用“密钥”类型的特征项对输入的明文进行加密,返回密文结果。
|
||||
|
||||
### 参数
|
||||
@@ -1013,6 +1043,7 @@ BIT_STATUS Bit_DecryptFeature(
|
||||
BIT_VOID *pPlainBuffer,
|
||||
BIT_UINT32 dataBufferSize);
|
||||
```
|
||||
|
||||
使用“密钥”类型的特征项对输入的密文进行解密,返回明文结果。
|
||||
|
||||
### 参数
|
||||
@@ -1043,6 +1074,7 @@ BIT_STATUS Bit_ReadFeature(
|
||||
BIT_UINT32 featureId,
|
||||
BIT_UINT32 *pFeatureValue);
|
||||
```
|
||||
|
||||
读取特征项的数据内容,可用于“只读”和“读写”特征类型。
|
||||
|
||||
### 参数
|
||||
@@ -1059,6 +1091,7 @@ BIT_STATUS Bit_WriteFeature(
|
||||
BIT_UINT32 featureId,
|
||||
BIT_UINT32 featureValue);
|
||||
```
|
||||
|
||||
更新“读写”类型的特征项的数据内容。
|
||||
|
||||
### 参数
|
||||
@@ -1069,7 +1102,6 @@ BIT_STATUS Bit_WriteFeature(
|
||||
|
||||
## 配置项操作
|
||||
|
||||
|
||||
### Bit_GetDataItem
|
||||
|
||||
```c
|
||||
@@ -1079,6 +1111,7 @@ BIT_STATUS Bit_GetDataItem (
|
||||
BIT_VOID *pDataItemValue,
|
||||
BIT_UINT32 *pDataItemValueSize)
|
||||
```
|
||||
|
||||
读取指定的配置项数据。
|
||||
|
||||
### 参数
|
||||
@@ -1097,6 +1130,7 @@ BIT_STATUS Bit_SetDataItem (
|
||||
BIT_VOID *pDataItemValue,
|
||||
BIT_UINT32 dataItemValueSize)
|
||||
```
|
||||
|
||||
创建或更新配置项。如果相同名称的配置项存在,则会更新其中的数据;否则将添加新的授权码配置项。
|
||||
|
||||
### 参数
|
||||
@@ -1113,6 +1147,7 @@ BIT_STATUS Bit_GetDataItemNum (
|
||||
BIT_HANDLE handle,
|
||||
BIT_UINT32 *pNum)
|
||||
```
|
||||
|
||||
此函数用于获取可访问配置项的数量,一般用于配置项的枚举操作。
|
||||
|
||||
### 参数
|
||||
@@ -1129,6 +1164,7 @@ BIT_STATUS Bit_GetDataItemName (
|
||||
BIT_CHAR *pDataItemName,
|
||||
BIT_UINT32 *pDataItemNameSize)
|
||||
```
|
||||
|
||||
根据配置项索引获取其名称,一般用于配置项的枚举操作。
|
||||
|
||||
### 参数
|
||||
@@ -1145,6 +1181,7 @@ BIT_STATUS Bit_RemoveDataItem (
|
||||
BIT_HANDLE handle,
|
||||
BIT_PCSTR szDataItemName)
|
||||
```
|
||||
|
||||
删除指定的配置项。该操作无法删除通过控制台设置的产品配置项或模版配置项。
|
||||
|
||||
### 参数
|
||||
@@ -1154,7 +1191,6 @@ BIT_STATUS Bit_RemoveDataItem (
|
||||
|
||||
## 信息获取
|
||||
|
||||
|
||||
### Bit_GetSessionInfo
|
||||
|
||||
```c
|
||||
@@ -1164,6 +1200,7 @@ BIT_STATUS Bit_GetSessionInfo (
|
||||
BIT_CHAR *pSessionInfo,
|
||||
BIT_UINT32 *pSessionInfoSize)
|
||||
```
|
||||
|
||||
获取当前会话信息,以字符串形式返回。根据获取的内容不同,返回结果可能是XML格式或非XML格式。返回数据中的日期项已根据客户端的本地时区进行调整。如果Login时未指定SN,返回串为当前系统所有可用SN的综合结果。
|
||||
|
||||
当函数返回BIT_ERR_BUFFER_SMALL时,pSessionInfoSize保存的是实际数据的大小。
|
||||
@@ -1242,6 +1279,7 @@ BIT_STATUS Bit_GetInfo (
|
||||
BIT_CHAR *pInfo,
|
||||
BIT_UINT32 *pInfoSize)
|
||||
```
|
||||
|
||||
获取本地授权信息。
|
||||
|
||||
如果要获取集团授权的信息,则szSN输入“`@bit://ip:port`”,会获取集团授权信息(仅支持type=BIT_INFO_SN)。
|
||||
@@ -1281,6 +1319,7 @@ BIT_STATUS Bit_GetServerInfo(
|
||||
BIT_CHAR *pServerInfo,
|
||||
BIT_UINT32 *pServerInfoSize);
|
||||
```
|
||||
|
||||
获取集团服务的License信息,数据以XML格式返回。调用此函数前客户端不需要执行登录操作。
|
||||
|
||||
### 参数
|
||||
@@ -1321,6 +1360,7 @@ BIT_STATUS Bit_GetServerInfo(
|
||||
……
|
||||
</features>
|
||||
```
|
||||
|
||||
1. 指定分组(group)查询
|
||||
|
||||
仅支持BIT_SERVER_INFO_SN_USERS、BIT_SERVER_INFO_FEATURE_USERS、BIT_SERVER_INFO_FEATURE_USERS_EX三种类型,通过name限定待查询的分组。
|
||||
@@ -1332,6 +1372,7 @@ BIT_STATUS Bit_GetServerInfo(
|
||||
……
|
||||
</groups>
|
||||
```
|
||||
|
||||
> 说明:通过Bit_SetCustomInfo的CUSTOM_GROUP_NAME(0xA)设置分组。
|
||||
|
||||
### 返回XML数据说明
|
||||
@@ -1360,6 +1401,7 @@ XML返回示例:
|
||||
BIT_STATUS Bit_GetVersion (
|
||||
BIT_UINT32 *pVersion)
|
||||
```
|
||||
|
||||
获取客户端安全库版本号。
|
||||
|
||||
### 参数
|
||||
@@ -1373,6 +1415,7 @@ BIT_STATUS Bit_GetNextHandle(
|
||||
BIT_HANDLE handle,
|
||||
BIT_HANDLE *pNextHandle)
|
||||
```
|
||||
|
||||
用来遍历当前进程内的handle。
|
||||
|
||||
### 参数
|
||||
@@ -1398,6 +1441,7 @@ BIT_STATUS Bit_TestBitService (
|
||||
BIT_UINT32 featureId,
|
||||
BIT_UCHAR *pApplicationData)
|
||||
```
|
||||
|
||||
测试集团授权的特征项是否可用,不会占用授权码或特征项的用户数。
|
||||
|
||||
### 参数
|
||||
@@ -1421,6 +1465,7 @@ BIT_STATUS Bit_GetProductPath(
|
||||
BIT_CHAR *pPath,
|
||||
BIT_UINT32 lenPath);
|
||||
```
|
||||
|
||||
获取授权存储目录。
|
||||
|
||||
### 参数
|
||||
@@ -1434,6 +1479,7 @@ BIT_STATUS Bit_GetProductPath(
|
||||
```c
|
||||
BIT_STATUS Bit_GetLastError();
|
||||
```
|
||||
|
||||
获取上一个API调用返回的错误码。
|
||||
|
||||
### 参数
|
||||
@@ -1442,7 +1488,6 @@ BIT_STATUS Bit_GetLastError();
|
||||
|
||||
## 属性设置
|
||||
|
||||
|
||||
### Bit_SetAttr
|
||||
|
||||
```c
|
||||
@@ -1451,6 +1496,7 @@ BIT_STATUS Bit_SetAttr (
|
||||
BIT_UINT32 type,
|
||||
BIT_VOID *pValue)
|
||||
```
|
||||
|
||||
设置全局配置或当前会话的配置。
|
||||
|
||||
### 参数
|
||||
@@ -1516,6 +1562,7 @@ BIT_STATUS Bit_SetProxy (
|
||||
BIT_PCSTR szUserID,
|
||||
BIT_PCSTR szPassword)
|
||||
```
|
||||
|
||||
设置代理服务的地址和端口。
|
||||
|
||||
### 参数
|
||||
@@ -1540,6 +1587,7 @@ BIT_STATUS Bit_SetCustomInfo (
|
||||
BIT_VOID *pInfoData,
|
||||
BIT_UINT32 infoDataSize)
|
||||
```
|
||||
|
||||
设置客户端运行自定义信息,需要在程序的最开始调用。
|
||||
|
||||
### 参数
|
||||
@@ -1589,6 +1637,7 @@ if (status == BIT_SUCCESS) {
|
||||
BIT_STATUS Bit_SetRootPath (
|
||||
BIT_PCSTR szPath)
|
||||
```
|
||||
|
||||
设置授权文件的存储路径。
|
||||
|
||||
### 参数
|
||||
@@ -1604,6 +1653,7 @@ BIT_STATUS Bit_SetLocalServer (
|
||||
BIT_UINT32 nPort,
|
||||
BIT_UINT32 nTimeoutSecondes)
|
||||
```
|
||||
|
||||
设置集团服务的地址和端口。
|
||||
|
||||
### 参数
|
||||
@@ -1615,7 +1665,6 @@ BIT_STATUS Bit_SetLocalServer (
|
||||
|
||||
## 借出操作
|
||||
|
||||
|
||||
### Bit_GetBorrowRequest
|
||||
|
||||
```c
|
||||
@@ -1626,6 +1675,7 @@ BIT_STATUS Bit_GetBorrowRequest(
|
||||
BIT_CHAR *pRequestInfo,
|
||||
BIT_UINT32 *pRequestInfoSize)
|
||||
```
|
||||
|
||||
获取借出请求串,用来离线借出。
|
||||
|
||||
### 参数
|
||||
@@ -1647,6 +1697,7 @@ BIT_STATUS Bit_GetBorrowFeatureRequest(
|
||||
BIT_CHAR *pRequestInfo,
|
||||
BIT_UINT32 *pRequestInfoSize)
|
||||
```
|
||||
|
||||
获取借出请求串,该接口支持指定特征项借出。
|
||||
|
||||
### 参数
|
||||
@@ -1684,6 +1735,7 @@ BIT_STATUS Bit_CheckOutSnEx(
|
||||
BIT_UCHAR *pApplicationData,
|
||||
BIT_UINT32 nDurationDays);
|
||||
```
|
||||
|
||||
从授权服务器在线借出一个完整的授权码,以允许客户端服务器单独使用。被借出的授权码必须具有可借出属性,并在客户端成功借出后减少一个可用用户数。被借出的用户数在到期后将自动返还给服务器。
|
||||
|
||||
### 参数
|
||||
@@ -1721,6 +1773,7 @@ BIT_STATUS Bit_CheckOut(
|
||||
BIT_UCHAR *pApplicationData,
|
||||
BIT_UINT32 nDurationDays)
|
||||
```
|
||||
|
||||
从授权服务器在线借出授权码或者特征项。
|
||||
|
||||
### 参数
|
||||
@@ -1740,6 +1793,7 @@ type:借出类型。目前仅支持ws,表示从外网借出(针对云授
|
||||
sn:指定借出的SN
|
||||
-->
|
||||
```
|
||||
|
||||
- **pFeatureList** xml结构,指定借出的特征项列表,如果不传则借出整个SN。
|
||||
|
||||
```xml
|
||||
@@ -1749,6 +1803,7 @@ sn:指定借出的SN
|
||||
<feature id='10'/>
|
||||
</features>
|
||||
```
|
||||
|
||||
当feature指定了借出时间,则会覆盖nDurationDays该时间,没有指定,则借出nDurationDays天。
|
||||
|
||||
借出feature时,如果指定了版本,则直接大于等于借出版本的特征项,只借一个,如果没有指定版本,则该特征项的所有版本都借出一个。
|
||||
@@ -1792,6 +1847,7 @@ BIT_STATUS Bit_CheckOutFeatures(
|
||||
BIT_UINT32 nFeatureInList,
|
||||
BIT_UINT32 nDurationDays);
|
||||
```
|
||||
|
||||
从集团授权服务器借出一组特征项,这些特征项必须包含在同一个授权码中。被借出的集团授权码必须具有可借出属性,并在客户端成功借出后减少一个可用用户数。被借出的用户数在到期后将自动返还给集团服务器。
|
||||
|
||||
### 参数
|
||||
@@ -1831,6 +1887,7 @@ BIT_STATUS Bit_CheckIn(
|
||||
BIT_UINT32 featureId,
|
||||
BIT_UCHAR *pApplicationData)
|
||||
```
|
||||
|
||||
提前返还从集团授权服务器借出的授权。要提前返还授权,该授权码必须具有允许提前返还属性。
|
||||
|
||||
### 参数
|
||||
@@ -1848,6 +1905,7 @@ BIT_STATUS Bit_CheckInEx(
|
||||
BIT_PCSTR szScope,
|
||||
BIT_UCHAR *pApplicationData)
|
||||
```
|
||||
|
||||
提前返还从授权服务器借出的授权。要提前返还授权,该授权码必须具有允许提前返还属性。
|
||||
|
||||
### 参数
|
||||
@@ -1861,6 +1919,7 @@ BIT_STATUS Bit_CheckInEx(
|
||||
<type>ws</type> <!-- type:归还类型,ws表示归还到云授权服务,默认是归还到集团授权服务 -->
|
||||
</scope>
|
||||
```
|
||||
|
||||
用于指定借出的参数,格式:wsxxxx,type设定为ws时表示从云授权服务器借出和归还。
|
||||
|
||||
- **pApplicationData** - [IN] 产品识别码。记录在接口定义文件中,与产品一一对应。
|
||||
@@ -1872,9 +1931,11 @@ BIT_STATUS Bit_ApplyBorrowInfo(
|
||||
BIT_UCHAR *pApplicationData,
|
||||
BIT_PCSTR pBorrowInfo)
|
||||
```
|
||||
|
||||
客户端应用离线借出串,Bit_ApplyUpdateInfo可以兼容该接口。
|
||||
|
||||
### 参数
|
||||
|
||||
- **pApplicationData** - [IN] 产品识别码。记录在接口定义文件中,与产品一一对应。
|
||||
- **pBorrowInfo** - [IN] 借出请求串。
|
||||
|
||||
|
||||
+62
-10
@@ -1,12 +1,11 @@
|
||||
# 比特授权云 · Java 语言接口(离线摘录)
|
||||
|
||||
> 本文档由官网页面离线摘录并整理排版,便于本地检索。官方地址:<https://doc.bitanswer.cn/docs/client-api/java-interface-v2/>
|
||||
> 本文档由官网页面离线摘录并整理排版,便于本地检索。官方地址:[https://doc.bitanswer.cn/docs/client-api/java-interface-v2/](https://doc.bitanswer.cn/docs/client-api/java-interface-v2/)
|
||||
|
||||
---
|
||||
|
||||
## 构造方法详细信息
|
||||
|
||||
|
||||
### BitAnswer
|
||||
|
||||
```java
|
||||
@@ -16,7 +15,6 @@ public BitAnswer(String url, String sn, LoginMode mode)
|
||||
|
||||
## 认证
|
||||
|
||||
|
||||
### login / loginEx
|
||||
|
||||
```java
|
||||
@@ -30,6 +28,7 @@ void loginEx (String url,
|
||||
String xmlScope,
|
||||
LoginMode mode)
|
||||
```
|
||||
|
||||
授权登录。初始化运行环境,获取操作句柄。必须在除升级函数之外的其它操作前执行。根据登录模式的不同可能需要连接授权服务器。
|
||||
|
||||
Login 等价于 LoginEx(featureId=0);当需要登录包含指定特征项的授权时才需要调用LoginEx。
|
||||
@@ -75,6 +74,7 @@ Login 等价于 LoginEx(featureId=0);当需要登录包含指定特征项
|
||||
void loginByToken (String url,
|
||||
String token)
|
||||
```
|
||||
|
||||
帐号授权的登录接口。仅支持两种认证方式,这里是使用比特授权云平台自己产生的access_token进行认证。
|
||||
|
||||
### 参数
|
||||
@@ -95,6 +95,7 @@ void loginByTokenEx (String url,
|
||||
String idpGuid,
|
||||
String grantType)
|
||||
```
|
||||
|
||||
帐号授权的登录接口。仅支持两种认证方式,这里是使用OIDC协议产生的id_token认证。
|
||||
|
||||
### 参数
|
||||
@@ -118,6 +119,7 @@ void loginByPassword (String url,
|
||||
String account,
|
||||
String password)
|
||||
```
|
||||
|
||||
通过用户名和密码登录帐号授权。
|
||||
|
||||
### 参数
|
||||
@@ -137,6 +139,7 @@ void loginByPassword (String url,
|
||||
```java
|
||||
void logout()
|
||||
```
|
||||
|
||||
此函数用于释放上下文句柄,退出登录状态,与Login相关接口一一对应。
|
||||
|
||||
### 参数
|
||||
@@ -152,6 +155,7 @@ void logout()
|
||||
```java
|
||||
String revoke (String sn)
|
||||
```
|
||||
|
||||
从客户端迁出已激活的浮动授权码。授权码迁出后,可以用于其它的客户端。根据输入参数的不同,本函数可用于在线或离线迁出。
|
||||
|
||||
### 参数
|
||||
@@ -168,6 +172,7 @@ String revoke (String sn)
|
||||
void revokeOnline (String url,
|
||||
String sn)
|
||||
```
|
||||
|
||||
从客户端迁出已激活的浮动授权码。授权码迁出后,可以用于其它的客户端。本函数需要进行网络连接。
|
||||
|
||||
### 参数
|
||||
@@ -184,6 +189,7 @@ void revokeOnline (String url,
|
||||
```java
|
||||
void removeSn (String sn)
|
||||
```
|
||||
|
||||
删除指定授权码在本机的授权数据。
|
||||
|
||||
### 参数
|
||||
@@ -199,6 +205,7 @@ void removeSn (String sn)
|
||||
```java
|
||||
int heartbeat()
|
||||
```
|
||||
|
||||
手动心跳,可以无限次调用,10s只会触发一次。
|
||||
|
||||
注:当自动心跳停止后,调用该接口可以尝试恢复自动心跳。
|
||||
@@ -218,6 +225,7 @@ String sessionControl (String url,
|
||||
String sessionId,
|
||||
SessionCtlType type)
|
||||
```
|
||||
|
||||
控制或设置session的信息。具体使用场景可参考《浏览器并发控制》文档。
|
||||
|
||||
### 参数
|
||||
@@ -243,6 +251,7 @@ String sessionControl (String url,
|
||||
void setSessionState (int state,
|
||||
byte[] pReserved)
|
||||
```
|
||||
|
||||
设置客户端的状态为空闲状态或繁忙状态或激活状态。
|
||||
|
||||
### 参数
|
||||
@@ -264,13 +273,13 @@ void setSessionState (int state,
|
||||
|
||||
## 激活升级
|
||||
|
||||
|
||||
### updateOnline
|
||||
|
||||
```java
|
||||
void updateOnline (String url,
|
||||
String sn)
|
||||
```
|
||||
|
||||
此函数用于与授权服务器在线连接,自动完成本地授权的升级操作。本函数需要进行网络连接。
|
||||
|
||||
### 参数
|
||||
@@ -288,6 +297,7 @@ void updateOnline (String url,
|
||||
String getRequestInfo (String sn,
|
||||
BindingType type)
|
||||
```
|
||||
|
||||
获取当前运行环境的升级请求码,用于发起本地授权激活及升级请求。
|
||||
|
||||
### 参数
|
||||
@@ -310,6 +320,7 @@ String getRequestInfo (String sn,
|
||||
```java
|
||||
String applyUpdateInfo (String updateInfo)
|
||||
```
|
||||
|
||||
应用升级码完成本地授权激活或升级。本函数必须在获取请求码的同一环境下执行。
|
||||
|
||||
### 参数
|
||||
@@ -327,6 +338,7 @@ String getUpdateInfo (String url,
|
||||
String sn,
|
||||
String requestInfo)
|
||||
```
|
||||
|
||||
使用请求码与授权服务器进行连接,获取升级码。本函数需要进行网络连接。
|
||||
|
||||
### 参数
|
||||
@@ -341,12 +353,12 @@ String getUpdateInfo (String url,
|
||||
|
||||
## 特征项操作
|
||||
|
||||
|
||||
### batchBegin
|
||||
|
||||
```java
|
||||
void batchBegin (BatchMode mode)
|
||||
```
|
||||
|
||||
开启批量Query模式,调用此API后调用的所有Query相关API,全部由Bit_batchEnd接口批量提交连接集团服务。
|
||||
|
||||
### 参数
|
||||
@@ -365,6 +377,7 @@ void batchBegin (BatchMode mode)
|
||||
```java
|
||||
int[] batchEnd()
|
||||
```
|
||||
|
||||
批量提交Query请求。
|
||||
|
||||
### 参数
|
||||
@@ -380,6 +393,7 @@ int[] batchEnd()
|
||||
```java
|
||||
int queryFeature (int featureId)
|
||||
```
|
||||
|
||||
开发商可以对软件的某个功能进行单独授权,当程序运行该模块时,可以通过该接口检查是否可用。
|
||||
|
||||
### 参数
|
||||
@@ -395,6 +409,7 @@ int queryFeature (int featureId)
|
||||
```java
|
||||
int releaseFeature (int featureId)
|
||||
```
|
||||
|
||||
释放所占用的用户数,该函数和Bit_QueryFeature一一对应。
|
||||
|
||||
### 参数
|
||||
@@ -413,6 +428,7 @@ int queryFeatureEx (int featureId,
|
||||
int required,
|
||||
String scope)
|
||||
```
|
||||
|
||||
集团授权专用,该接口支持占用指定用户数,支持通过特征项版本进行检查。
|
||||
|
||||
### 参数
|
||||
@@ -439,6 +455,7 @@ int releaseFeatureEx (int featureId,
|
||||
int consumed,
|
||||
String scope)
|
||||
```
|
||||
|
||||
集团授权专用,释放指定的用户数。该接口与Bit_QueryFeatureEx对应。
|
||||
|
||||
### 参数
|
||||
@@ -459,6 +476,7 @@ long queryFeatureEx2 (String featureName,
|
||||
int required,
|
||||
String scope)
|
||||
```
|
||||
|
||||
可以使用“特征项名称 + 特征项版本”进行用户数占用,支持队列模式。
|
||||
|
||||
### 参数
|
||||
@@ -486,6 +504,7 @@ long queryFeatureEx2 (String featureName,
|
||||
void releaseFeatureEx2 (byte[] ticket,
|
||||
int consumed)
|
||||
```
|
||||
|
||||
释放ticket所占用的用户数。该函数和Bit_QueryFeatureEx2一一对应。
|
||||
|
||||
### 参数
|
||||
@@ -503,6 +522,7 @@ void releaseFeatureEx2 (byte[] ticket,
|
||||
int getFeatureInfo2 (String featureName,
|
||||
String scope)
|
||||
```
|
||||
|
||||
检查特征项是否存在,不会占用授权码或特征项的用户数,获取特征项的剩余有效期。
|
||||
|
||||
### 参数
|
||||
@@ -520,6 +540,7 @@ int getFeatureInfo2 (String featureName,
|
||||
String getFeatureInfoEx2 (String featureName,
|
||||
String scope)
|
||||
```
|
||||
|
||||
获取指定feature的信息,以XML格式返回。
|
||||
|
||||
### 参数
|
||||
@@ -544,6 +565,7 @@ String getFeatureInfoEx2 (String featureName,
|
||||
String getTicketInfo (byte[] ticket,
|
||||
int type)
|
||||
```
|
||||
|
||||
获取ticket信息。
|
||||
|
||||
### 参数
|
||||
@@ -568,6 +590,7 @@ int convertFeature (int featureId,
|
||||
int para3,
|
||||
int para4)
|
||||
```
|
||||
|
||||
使用“算法”类型的特征项对输入参数进行变换操作,得到唯一对应的4字节结果。
|
||||
|
||||
### 参数
|
||||
@@ -588,6 +611,7 @@ int convertFeature (int featureId,
|
||||
byte[] encryptFeature (int featureId,
|
||||
byte[] pPlainBuffer)
|
||||
```
|
||||
|
||||
使用“密钥”类型的特征项对输入的明文进行加密,返回密文结果。
|
||||
|
||||
### 参数
|
||||
@@ -605,6 +629,7 @@ byte[] encryptFeature (int featureId,
|
||||
byte[] decryptFeature (int featureId,
|
||||
byte[] pCipherBuffer)
|
||||
```
|
||||
|
||||
使用“密钥”类型的特征项对输入的密文进行解密,返回明文结果。
|
||||
|
||||
### 参数
|
||||
@@ -621,6 +646,7 @@ byte[] decryptFeature (int featureId,
|
||||
```java
|
||||
int readFeature (int featureId)
|
||||
```
|
||||
|
||||
读取特征项的数据内容,可用于“只读”和“读写”特征类型。
|
||||
|
||||
### 参数
|
||||
@@ -637,6 +663,7 @@ int readFeature (int featureId)
|
||||
void writeFeature (int featureId,
|
||||
int featureValue)
|
||||
```
|
||||
|
||||
更新“读写”类型的特征项的数据内容。
|
||||
|
||||
### 参数
|
||||
@@ -650,12 +677,12 @@ void writeFeature (int featureId,
|
||||
|
||||
## 配置项操作
|
||||
|
||||
|
||||
### getDataItem
|
||||
|
||||
```java
|
||||
byte[] getDataItem (String dataItemName)
|
||||
```
|
||||
|
||||
读取指定的配置项数据。
|
||||
|
||||
### 参数
|
||||
@@ -672,6 +699,7 @@ byte[] getDataItem (String dataItemName)
|
||||
void setDataItem (String dataItemName,
|
||||
byte[] dataItemValue)
|
||||
```
|
||||
|
||||
创建或更新配置项。如果相同名称的配置项存在,则会更新其中的数据;否则将添加新的授权码配置项。
|
||||
|
||||
### 参数
|
||||
@@ -688,6 +716,7 @@ void setDataItem (String dataItemName,
|
||||
```java
|
||||
int getDataItemNum()
|
||||
```
|
||||
|
||||
此函数用于获取可访问配置项的数量,一般用于配置项的枚举操作。
|
||||
|
||||
### 参数
|
||||
@@ -703,6 +732,7 @@ int getDataItemNum()
|
||||
```java
|
||||
String getDataItemName (int index)
|
||||
```
|
||||
|
||||
根据配置项索引获取其名称,一般用于配置项的枚举操作。
|
||||
|
||||
### 参数
|
||||
@@ -718,6 +748,7 @@ String getDataItemName (int index)
|
||||
```java
|
||||
void removeDataItem (String dataItemName)
|
||||
```
|
||||
|
||||
删除指定的配置项。该操作无法删除通过控制台设置的产品配置项或模版配置项。
|
||||
|
||||
### 参数
|
||||
@@ -730,12 +761,12 @@ void removeDataItem (String dataItemName)
|
||||
|
||||
## 信息获取
|
||||
|
||||
|
||||
### getSessionInfo
|
||||
|
||||
```java
|
||||
String getSessionInfo (SessionType type)
|
||||
```
|
||||
|
||||
获取当前会话信息,以字符串形式返回。根据获取的内容不同,返回结果可能是XML格式或非XML格式。返回数据中的日期项已根据客户端的本地时区进行调整。如果Login时未指定SN,返回串为当前系统所有可用SN的综合结果。
|
||||
|
||||
### 参数
|
||||
@@ -771,6 +802,7 @@ String getSessionInfo (SessionType type)
|
||||
String getInfo (String sn,
|
||||
InfoType type)
|
||||
```
|
||||
|
||||
获取本地授权信息。
|
||||
|
||||
### 参数
|
||||
@@ -800,6 +832,7 @@ String getServerInfo (String url,
|
||||
String scope,
|
||||
ServerInfoType type)
|
||||
```
|
||||
|
||||
获取集团服务的license信息,数据以XML格式返回。调用此函数前客户端不需要执行登录操作。
|
||||
|
||||
### 参数
|
||||
@@ -824,6 +857,7 @@ String getServerInfo (String url,
|
||||
```java
|
||||
int getVersion()
|
||||
```
|
||||
|
||||
获取客户端安全库版本号。
|
||||
|
||||
### 参数
|
||||
@@ -841,6 +875,7 @@ void testBitService (String url,
|
||||
String sn,
|
||||
int featureId)
|
||||
```
|
||||
|
||||
测试集团授权的特征项是否可用,不会占用授权码或特征项的用户数。
|
||||
|
||||
### 参数
|
||||
@@ -858,6 +893,7 @@ void testBitService (String url,
|
||||
```java
|
||||
String getProductPath()
|
||||
```
|
||||
|
||||
获取授权存储目录。
|
||||
|
||||
### 参数
|
||||
@@ -873,6 +909,7 @@ String getProductPath()
|
||||
```java
|
||||
int getLastError()
|
||||
```
|
||||
|
||||
获取上一个API调用返回的错误码。
|
||||
|
||||
### 参数
|
||||
@@ -889,13 +926,13 @@ int getLastError()
|
||||
|
||||
## 属性设置
|
||||
|
||||
|
||||
### setAttr
|
||||
|
||||
```java
|
||||
void setAttr (int type,
|
||||
byte[] pValue)
|
||||
```
|
||||
|
||||
设置全局配置或当前会话的配置。
|
||||
|
||||
### 参数
|
||||
@@ -924,6 +961,7 @@ void setProxy (String hostName,
|
||||
String userId,
|
||||
String password)
|
||||
```
|
||||
|
||||
设置代理服务的地址和端口。
|
||||
|
||||
### 参数
|
||||
@@ -943,6 +981,7 @@ void setProxy (String hostName,
|
||||
void setCustomInfo (int infoId,
|
||||
String infoData)
|
||||
```
|
||||
|
||||
设置客户端运行自定义信息,需要在程序的最开始调用。infoId定义详见CustomInfo类型。
|
||||
|
||||
### 参数
|
||||
@@ -958,6 +997,7 @@ void setCustomInfo (int infoId,
|
||||
void setCustomInfo (int infoId,
|
||||
int infoData)
|
||||
```
|
||||
|
||||
设置客户端运行自定义信息,需要在程序的最开始调用。infoId定义详见CustomInfo类型。
|
||||
|
||||
### 参数
|
||||
@@ -980,6 +1020,7 @@ void setCustomInfo (int infoId,
|
||||
```java
|
||||
void setRootPath (String rootPath)
|
||||
```
|
||||
|
||||
设置授权文件的存储路径。
|
||||
|
||||
### 参数
|
||||
@@ -997,6 +1038,7 @@ void setLocalServer (String hostName,
|
||||
int port,
|
||||
int timeout)
|
||||
```
|
||||
|
||||
设置集团服务的地址和端口。
|
||||
|
||||
### 参数
|
||||
@@ -1011,13 +1053,13 @@ void setLocalServer (String hostName,
|
||||
|
||||
## 借出操作
|
||||
|
||||
|
||||
### getBorrowRequest
|
||||
|
||||
```java
|
||||
String getBorrowRequest (String sn,
|
||||
int durationDay)
|
||||
```
|
||||
|
||||
获取借出请求串,用来离线借出。
|
||||
|
||||
### 参数
|
||||
@@ -1035,6 +1077,7 @@ String getBorrowRequest (String sn,
|
||||
String getBorrowFeatureRequest (int durationDay,
|
||||
String borrowScope)
|
||||
```
|
||||
|
||||
获取借出请求串,该接口支持指定特征项借出。
|
||||
|
||||
### 参数
|
||||
@@ -1056,6 +1099,7 @@ String getBorrowFeatureRequest (int durationDay,
|
||||
void checkOutSn (String url,
|
||||
int featureId)
|
||||
```
|
||||
|
||||
从授权服务器在线借出一个完整的授权码,以允许客户端服务器单独使用。被借出的授权码必须具有可借出属性,并在客户端成功借出后减少一个可用用户数。被借出的用户数在到期后将自动返还给服务器。
|
||||
|
||||
### 参数
|
||||
@@ -1075,6 +1119,7 @@ void checkOutSnEx (String url,
|
||||
String xmlScope,
|
||||
int durationDays)
|
||||
```
|
||||
|
||||
从授权服务器在线借出一个完整的授权码,以允许客户端服务器单独使用。被借出的授权码必须具有可借出属性,并在客户端成功借出后减少一个可用用户数。被借出的用户数在到期后将自动返还给服务器。
|
||||
|
||||
### 参数
|
||||
@@ -1096,6 +1141,7 @@ void checkOut (String url,
|
||||
String featureList,
|
||||
int durationDays)
|
||||
```
|
||||
|
||||
从授权服务器在线借出授权码或者特征项。
|
||||
|
||||
### 参数
|
||||
@@ -1113,6 +1159,7 @@ void checkOut (String url,
|
||||
type:借出类型。目前仅支持ws,表示从外网借出(针对云授权和集团授权)
|
||||
sn:指定借出的SN
|
||||
```
|
||||
|
||||
- **featureList** - [IN] 特征项列表,指定借出的特征项列表,如果不传则借出整个SN。示例:
|
||||
|
||||
```xml
|
||||
@@ -1125,6 +1172,7 @@ sn:指定借出的SN
|
||||
当feature指定了借出时间,则会覆盖nDurationDays该时间,没有指定,则借出nDurationDays天。
|
||||
借出feature时,如果指定了版本,则直接大于等于借出版本的特征项,只借一个,如果没有指定版本,则该特征项的所有版本都借出一个。
|
||||
```
|
||||
|
||||
- **durationDays** - [IN] 借出有效期,单位为天,需小于等于授权码允许的最大借出天数。
|
||||
|
||||
### 返回
|
||||
@@ -1138,6 +1186,7 @@ void checkOutFeatures (String url,
|
||||
int[] featureList,
|
||||
int durationDays)
|
||||
```
|
||||
|
||||
从集团授权服务器借出一组特征项,这些特征项必须包含在同一个授权码中。被借出的集团授权码必须具有可借出属性,并在客户端成功借出后减少一个可用用户数。被借出的用户数在到期后将自动返还给集团服务器。
|
||||
|
||||
### 参数
|
||||
@@ -1156,6 +1205,7 @@ void checkOutFeatures (String url,
|
||||
void checkIn (String url,
|
||||
int featureId)
|
||||
```
|
||||
|
||||
提前返还从集团授权服务器借出的授权。要提前返还授权,该授权码必须具有允许提前返还属性。
|
||||
|
||||
### 参数
|
||||
@@ -1174,6 +1224,7 @@ void checkInEx (String url,
|
||||
int featureId,
|
||||
String xmlScope)
|
||||
```
|
||||
|
||||
提前返还从授权服务器借出的授权。要提前返还授权,该授权码必须具有允许提前返还属性。
|
||||
|
||||
### 参数
|
||||
@@ -1191,6 +1242,7 @@ void checkInEx (String url,
|
||||
```java
|
||||
void ApplyBorrowInfo (string borrowInfo)
|
||||
```
|
||||
|
||||
客户端应用离线借出串,ApplyUpdateInfo可以兼容该接口。
|
||||
|
||||
### 参数
|
||||
@@ -1199,4 +1251,4 @@ void ApplyBorrowInfo (string borrowInfo)
|
||||
|
||||
### 返回
|
||||
|
||||
无
|
||||
无
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"provider": "bitanswer",
|
||||
"scenario": "floating",
|
||||
"bitanswer": {
|
||||
"url": "https://cloud.bitanswer.example/e3",
|
||||
"loginMode": "REMOTE"
|
||||
},
|
||||
"features": {
|
||||
"face": { "bitanswerFeatureId": 301 }
|
||||
},
|
||||
"floating": {
|
||||
"projectId": "migrant-flow-prj-2026-001",
|
||||
"projectName": "某市流动人口人像核验",
|
||||
"contractRef": "PO-2026-8848"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"provider": "bitanswer",
|
||||
"scenario": "school",
|
||||
"bitanswer": {
|
||||
"url": "https://cloud.bitanswer.example/e3",
|
||||
"loginMode": "AUTO",
|
||||
"sn": ""
|
||||
},
|
||||
"features": {
|
||||
"face": { "bitanswerFeatureId": 201 },
|
||||
"expression": { "bitanswerFeatureId": 202 }
|
||||
},
|
||||
"school": {
|
||||
"edgeDeviceId": "classroom-gate-01",
|
||||
"tenantId": "school-district-demo"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"provider": "selfhosted",
|
||||
"scenario": "school",
|
||||
"selfhosted": {
|
||||
"baseUrl": "https://license.internal.example/api/v1",
|
||||
"tenantKey": "district-west"
|
||||
},
|
||||
"features": {
|
||||
"face": {},
|
||||
"expression": {}
|
||||
},
|
||||
"school": {
|
||||
"edgeDeviceId": "gate-02"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"provider": "bitanswer",
|
||||
"scenario": "wharf",
|
||||
"bitanswer": {
|
||||
"url": "bit://license.example.com:8273",
|
||||
"loginMode": "AUTO",
|
||||
"rootPath": "/var/lib/craftlabs/bitanswer"
|
||||
},
|
||||
"features": {
|
||||
"container_number_detect": { "bitanswerFeatureId": 101 },
|
||||
"container_number_recognize": { "bitanswerFeatureId": 102 },
|
||||
"iso_detect": { "bitanswerFeatureId": 103 },
|
||||
"iso_recognize": { "bitanswerFeatureId": 104 }
|
||||
},
|
||||
"wharf": {
|
||||
"topology": "group",
|
||||
"groupServiceUrl": "bit://license.example.com:8273",
|
||||
"notes": "边设备集中连集团服务;特征项与控制台产品一致后替换 id。"
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
import cn.craftlabs.auth.AuthProvider;
|
||||
import cn.craftlabs.auth.AuthResult;
|
||||
import cn.craftlabs.auth.bitanswer.BitAnswerProvider;
|
||||
import cn.craftlabs.auth.config.AuthConfig;
|
||||
import cn.craftlabs.auth.config.AuthConfigException;
|
||||
import cn.craftlabs.auth.config.AuthConfigs;
|
||||
|
||||
/**
|
||||
* 演示:通过 {@link BitAnswerProvider} 完成初始化与许可校验。
|
||||
* 演示:校验 {@code config_json} 后初始化并完成许可校验。
|
||||
*
|
||||
* <p>编译时需将 {@code craftlabs-auth-core} 与 Jackson 置于 classpath(与 Maven 模块依赖一致)。
|
||||
*
|
||||
* <p>版权所有 © 广州创飞人工智能技术有限公司
|
||||
*
|
||||
@@ -11,8 +16,30 @@ import cn.craftlabs.auth.bitanswer.BitAnswerProvider;
|
||||
*/
|
||||
public class ExampleApp {
|
||||
public static void main(String[] args) {
|
||||
String json =
|
||||
"""
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"provider": "bitanswer",
|
||||
"scenario": "school",
|
||||
"bitanswer": { "url": "https://example.invalid/bitanswer", "loginMode": "AUTO" },
|
||||
"features": {
|
||||
"face": { "bitanswerFeatureId": 201 },
|
||||
"expression": { "bitanswerFeatureId": 202 }
|
||||
},
|
||||
"school": { "edgeDeviceId": "demo-edge-01", "tenantId": "demo-tenant" }
|
||||
}
|
||||
""";
|
||||
try {
|
||||
AuthConfig cfg = AuthConfigs.parse(json);
|
||||
System.out.println("scenario=" + cfg.scenario() + ", face id=" + cfg.bitanswerFeatureId("face"));
|
||||
} catch (AuthConfigException e) {
|
||||
System.err.println("config invalid: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
try (AuthProvider p = new BitAnswerProvider()) {
|
||||
AuthResult r = p.initialize("{}");
|
||||
AuthResult r = p.initialize(json);
|
||||
System.out.println("init: " + r.isSuccess() + " " + r.getMessage());
|
||||
r = p.checkLicense();
|
||||
System.out.println("check: " + r.isSuccess() + " " + r.getMessage());
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
# CraftLabs 授权 SDK — 发布与完整性
|
||||
|
||||
对齐架构文档 [SYSTEM_ARCHITECTURE §9.8](../docs/engineering/SYSTEM_ARCHITECTURE.md):官方渠道、**SHA-256 清单**、**GPG 签名(建议)**、`java` 与 `native` **同 Git tag**。
|
||||
|
||||
## 1. 发布前检查
|
||||
|
||||
- [ ] `mvn -f java/pom.xml verify` 通过(JDK 17+)。
|
||||
- [ ] `native` 已在各目标平台完成构建,且与本次 **同一 tag** 一并交付。
|
||||
- [ ] `CHANGELOG`(或发布说明)写明 **比特 SDK / 运行时** 兼容版本。
|
||||
|
||||
## 2. 生成 SHA256SUMS(必做)
|
||||
|
||||
在仓库根目录执行(会先 `mvn -DskipTests package`):
|
||||
|
||||
```bash
|
||||
chmod +x scripts/sdk-release-checksums.sh
|
||||
./scripts/sdk-release-checksums.sh --output dist/sdk-release
|
||||
```
|
||||
|
||||
已构建过时跳过 Maven:
|
||||
|
||||
```bash
|
||||
./scripts/sdk-release-checksums.sh --no-mvn --output dist/sdk-release
|
||||
```
|
||||
|
||||
把 **本机构建出的 Native** 一并写入清单(路径相对于仓库根,便于客户校验):
|
||||
|
||||
```bash
|
||||
./scripts/sdk-release-checksums.sh --output dist/sdk-release --native-path "$(pwd)/native/build"
|
||||
```
|
||||
|
||||
含完整测试的构建后再生成清单:
|
||||
|
||||
```bash
|
||||
./scripts/sdk-release-checksums.sh --verify --output dist/sdk-release
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
- `dist/sdk-release/SHA256SUMS` — 每行:`哈希 相对路径`
|
||||
- `dist/sdk-release/RELEASE-MANIFEST.txt` — 提交 SHA、UTC 时间
|
||||
|
||||
**客户校验**(在克隆/解压后的仓库根或同目录结构下):
|
||||
|
||||
```bash
|
||||
sha256sum -c dist/sdk-release/SHA256SUMS
|
||||
```
|
||||
|
||||
macOS:
|
||||
|
||||
```bash
|
||||
shasum -a 256 -c dist/sdk-release/SHA256SUMS
|
||||
```
|
||||
|
||||
对 `SHA256SUMS` 本身做 **分离签名**(本机已配置 GPG):
|
||||
|
||||
```bash
|
||||
SIGN=1 ./scripts/sdk-release-checksums.sh --no-mvn --output dist/sdk-release
|
||||
```
|
||||
|
||||
生成 `SHA256SUMS.asc`;客户使用公布的公钥:`gpg --verify SHA256SUMS.asc SHA256SUMS`。
|
||||
|
||||
## 3. Maven JAR 的 GPG 签名(强烈建议)
|
||||
|
||||
父 POM 已配置 `maven-gpg-plugin`,**默认跳过**(`gpg.skip=true`),不影响日常 `verify`。
|
||||
|
||||
发布前在已导入私钥的机器上:
|
||||
|
||||
```bash
|
||||
gpg --version # 确认可用
|
||||
mvn -f java/pom.xml -Prelease-sign verify
|
||||
```
|
||||
|
||||
各 **可发布模块**(`craftlabs-auth-core`、`craftlabs-auth-bitanswer`、`craftlabs-auth-selfhosted`)的 `target/*.jar` 旁会出现 **`.asc`**。`craftlabs-auth-tests` 模块固定 **不签名**。
|
||||
|
||||
若无私钥或未就绪,可只发 **SHA256SUMS**;待密钥就绪后再打开 `-Prelease-sign`。
|
||||
|
||||
### CI / 无人值守(可选)
|
||||
|
||||
在构建机配置 `MAVEN_GPG_PASSPHRASE` 等环境变量,或使用 `gpg-agent`;勿将私钥提交仓库。GitHub Actions 可用 `GPG_PRIVATE_KEY` secret + [crazy-max/ghaction-import-gpg](https://github.com/crazy-max/ghaction-import-gpg) 导入后再执行 `mvn -Prelease-sign verify`。
|
||||
|
||||
## 4. GitHub Release 建议资产
|
||||
|
||||
每个 **tag** 上传:
|
||||
|
||||
1. 三个 **release JAR**(及对应 **.asc**,若已签名)
|
||||
2. 各平台 **Native** 压缩包
|
||||
3. **`SHA256SUMS`** 与 **`SHA256SUMS.asc`**
|
||||
4. 固定页面公布 **GPG 公钥指纹** 与下载说明
|
||||
|
||||
---
|
||||
|
||||
版权所有 © 广州创飞人工智能技术有限公司(以项目实际声明为准)。
|
||||
@@ -13,4 +13,21 @@
|
||||
<artifactId>craftlabs-auth-core</artifactId>
|
||||
<name>CraftLabs Auth — core API</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.networknt</groupId>
|
||||
<artifactId>json-schema-validator</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -3,6 +3,9 @@ package cn.craftlabs.auth;
|
||||
/**
|
||||
* 授权能力的统一契约:初始化、激活、校验许可、查询特性与释放等生命周期方法。
|
||||
*
|
||||
* <p>{@link #initialize(String)} 的 JSON 建议使用 {@link cn.craftlabs.auth.config.AuthConfigs#parse(String)}
|
||||
* 先校验后再传入,格式见仓库 {@code schemas/craftlabs-auth-config.schema.json} 与 {@code examples/config/}。
|
||||
*
|
||||
* <p>实现类负责加载对应 native 或远端适配器;调用方应在不再使用时调用 {@link #close()} 释放底层资源。
|
||||
*
|
||||
* <p>版权所有 © 广州创飞人工智能技术有限公司
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package cn.craftlabs.auth.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* {@link cn.craftlabs.auth.AuthProvider#initialize(String)} 所用 JSON 的配置模型,与 {@code
|
||||
* schemas/craftlabs-auth-config.schema.json} 对齐。
|
||||
*
|
||||
* <p>版权所有 © 广州创飞人工智能技术有限公司
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public record AuthConfig(
|
||||
@JsonProperty("schemaVersion") int schemaVersion,
|
||||
@JsonProperty("provider") String provider,
|
||||
@JsonProperty("scenario") String scenario,
|
||||
@JsonProperty("bitanswer") BitanswerConfigSection bitanswer,
|
||||
@JsonProperty("selfhosted") SelfhostedConfigSection selfhosted,
|
||||
@JsonProperty("features") Map<String, FeatureMapping> features,
|
||||
@JsonProperty("wharf") WharfScenarioSection wharf,
|
||||
@JsonProperty("school") SchoolScenarioSection school,
|
||||
@JsonProperty("floating") FloatingScenarioSection floating) {
|
||||
|
||||
public AuthConfig {
|
||||
features = features == null ? Map.of() : Collections.unmodifiableMap(new LinkedHashMap<>(features));
|
||||
provider = Objects.requireNonNullElse(provider, "");
|
||||
scenario = Objects.requireNonNullElse(scenario, "");
|
||||
}
|
||||
|
||||
/** 逻辑特性键对应的比特特征 id;未配置或非数值映射时返回 {@code null}。 */
|
||||
public Integer bitanswerFeatureId(String logicalFeatureKey) {
|
||||
FeatureMapping m = features.get(logicalFeatureKey);
|
||||
return m != null ? m.bitanswerFeatureId() : null;
|
||||
}
|
||||
|
||||
/** 逻辑特性键对应的比特特征名称;未配置时返回 {@code null}。 */
|
||||
public String bitanswerFeatureName(String logicalFeatureKey) {
|
||||
FeatureMapping m = features.get(logicalFeatureKey);
|
||||
return m != null ? m.bitanswerFeatureName() : null;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package cn.craftlabs.auth.config;
|
||||
|
||||
/**
|
||||
* {@link AuthConfigs#parse(String)} 或校验失败时抛出。
|
||||
*
|
||||
* <p>版权所有 © 广州创飞人工智能技术有限公司
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
public final class AuthConfigException extends Exception {
|
||||
|
||||
public AuthConfigException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AuthConfigException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package cn.craftlabs.auth.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 解析并校验 {@link cn.craftlabs.auth.AuthProvider#initialize(String)} 的 JSON 配置。
|
||||
*
|
||||
* <p>版权所有 © 广州创飞人工智能技术有限公司
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
public final class AuthConfigs {
|
||||
|
||||
/** 与 {@code schemas/craftlabs-auth-config.schema.json} 中 {@code schemaVersion} 一致。 */
|
||||
public static final int SCHEMA_VERSION = 1;
|
||||
|
||||
private static final ObjectMapper MAPPER =
|
||||
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
|
||||
private AuthConfigs() {}
|
||||
|
||||
/** 解析 JSON 并执行 {@link #validate(AuthConfig)}。 */
|
||||
public static AuthConfig parse(String json) throws AuthConfigException {
|
||||
if (json == null || json.isBlank()) {
|
||||
throw new AuthConfigException("config JSON is null or blank");
|
||||
}
|
||||
try {
|
||||
AuthConfig cfg = MAPPER.readValue(json, AuthConfig.class);
|
||||
validate(cfg);
|
||||
return cfg;
|
||||
} catch (JsonProcessingException e) {
|
||||
String msg = e.getOriginalMessage() != null ? e.getOriginalMessage() : e.getMessage();
|
||||
throw new AuthConfigException("Invalid config JSON: " + msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/** 将配置写回 JSON(便于日志脱敏后落盘或调试)。 */
|
||||
public static String toJson(AuthConfig config) throws AuthConfigException {
|
||||
try {
|
||||
return MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(config);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new AuthConfigException("Failed to serialize config", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验必填组合;通过后可安全交给 native / 供应商实现。
|
||||
*
|
||||
* @throws AuthConfigException 校验失败,消息为多条原因拼接
|
||||
*/
|
||||
public static void validate(AuthConfig c) throws AuthConfigException {
|
||||
List<String> err = new ArrayList<>();
|
||||
|
||||
if (c.schemaVersion() != SCHEMA_VERSION) {
|
||||
err.add("schemaVersion must be " + SCHEMA_VERSION);
|
||||
}
|
||||
|
||||
String provider = norm(c.provider());
|
||||
if (provider.isEmpty()) {
|
||||
err.add("provider is required");
|
||||
} else if (!provider.equals("bitanswer") && !provider.equals("selfhosted")) {
|
||||
err.add("provider must be bitanswer or selfhosted");
|
||||
}
|
||||
|
||||
String scenario = norm(c.scenario());
|
||||
if (scenario.isEmpty()) {
|
||||
err.add("scenario is required");
|
||||
} else if (!scenario.equals("wharf") && !scenario.equals("school") && !scenario.equals("floating")) {
|
||||
err.add("scenario must be wharf, school, or floating");
|
||||
}
|
||||
|
||||
if (provider.equals("bitanswer")) {
|
||||
if (c.bitanswer() == null) {
|
||||
err.add("bitanswer section is required when provider=bitanswer");
|
||||
} else if (isBlank(c.bitanswer().url())) {
|
||||
err.add("bitanswer.url is required and must be non-blank");
|
||||
}
|
||||
}
|
||||
|
||||
if (provider.equals("selfhosted")) {
|
||||
if (c.selfhosted() == null) {
|
||||
err.add("selfhosted section is required when provider=selfhosted");
|
||||
} else if (isBlank(c.selfhosted().baseUrl())) {
|
||||
err.add("selfhosted.baseUrl is required and must be non-blank");
|
||||
}
|
||||
}
|
||||
|
||||
if (scenario.equals("floating")) {
|
||||
if (c.floating() == null || isBlank(c.floating().projectId())) {
|
||||
err.add("floating.projectId is required when scenario=floating");
|
||||
}
|
||||
}
|
||||
|
||||
if (!err.isEmpty()) {
|
||||
throw new AuthConfigException(String.join("; ", err));
|
||||
}
|
||||
}
|
||||
|
||||
private static String norm(String s) {
|
||||
return s == null ? "" : s.trim().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
private static boolean isBlank(String s) {
|
||||
return s == null || s.trim().isEmpty();
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package cn.craftlabs.auth.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* {@code config_json} 中与比特安索客户端相关的字段子集。
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public record BitanswerConfigSection(
|
||||
@JsonProperty("url") String url,
|
||||
@JsonProperty("loginMode") String loginMode,
|
||||
@JsonProperty("rootPath") String rootPath,
|
||||
@JsonProperty("sn") String sn,
|
||||
@JsonProperty("applicationData") String applicationData) {}
|
||||
@@ -0,0 +1,14 @@
|
||||
package cn.craftlabs.auth.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* 逻辑特性键(如 {@code face})到比特特征项的映射;至少填 id 或 name 之一即可在实现层选用。
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public record FeatureMapping(
|
||||
@JsonProperty("bitanswerFeatureId") Integer bitanswerFeatureId,
|
||||
@JsonProperty("bitanswerFeatureName") String bitanswerFeatureName) {}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package cn.craftlabs.auth.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/** 流动人口按项目授权场景补充字段。 */
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public record FloatingScenarioSection(
|
||||
@JsonProperty("projectId") String projectId,
|
||||
@JsonProperty("projectName") String projectName,
|
||||
@JsonProperty("contractRef") String contractRef) {}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package cn.craftlabs.auth.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/** 学校按边设备运营场景补充字段。 */
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public record SchoolScenarioSection(
|
||||
@JsonProperty("edgeDeviceId") String edgeDeviceId,
|
||||
@JsonProperty("tenantId") String tenantId) {}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package cn.craftlabs.auth.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* {@code provider=selfhosted} 时的 HTTP 后端参数。
|
||||
*
|
||||
* @author huangping@craftlabs.cn
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public record SelfhostedConfigSection(
|
||||
@JsonProperty("baseUrl") String baseUrl,
|
||||
@JsonProperty("tenantKey") String tenantKey) {}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package cn.craftlabs.auth.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/** 码头 / 集中授权场景补充字段。 */
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public record WharfScenarioSection(
|
||||
@JsonProperty("topology") String topology,
|
||||
@JsonProperty("groupServiceUrl") String groupServiceUrl,
|
||||
@JsonProperty("notes") String notes) {}
|
||||
@@ -0,0 +1,78 @@
|
||||
package cn.craftlabs.auth.config;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AuthConfigsTest {
|
||||
|
||||
@Test
|
||||
void parseWharfExampleFromClasspath() throws Exception {
|
||||
String json = readClasspath("examples/config/wharf.bitanswer.json");
|
||||
AuthConfig c = AuthConfigs.parse(json);
|
||||
assertEquals(1, c.schemaVersion());
|
||||
assertEquals("bitanswer", c.provider());
|
||||
assertEquals("wharf", c.scenario());
|
||||
assertNotNull(c.bitanswer());
|
||||
assertTrue(c.bitanswer().url().startsWith("bit://"));
|
||||
assertEquals(101, c.bitanswerFeatureId("container_number_detect"));
|
||||
assertEquals("group", c.wharf().topology());
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseSchoolExample() throws Exception {
|
||||
String json = readClasspath("examples/config/school.bitanswer.json");
|
||||
AuthConfig c = AuthConfigs.parse(json);
|
||||
assertEquals("school", c.scenario());
|
||||
assertEquals(201, c.bitanswerFeatureId("face"));
|
||||
assertEquals("classroom-gate-01", c.school().edgeDeviceId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseFloatingExample_requiresProjectId() throws Exception {
|
||||
String json = readClasspath("examples/config/floating.bitanswer.json");
|
||||
AuthConfig c = AuthConfigs.parse(json);
|
||||
assertEquals("floating", c.scenario());
|
||||
assertEquals("migrant-flow-prj-2026-001", c.floating().projectId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateFails_whenFloatingWithoutProject() {
|
||||
String json =
|
||||
"""
|
||||
{"schemaVersion":1,"provider":"bitanswer","scenario":"floating",\
|
||||
"bitanswer":{"url":"http://x"},"floating":{}}\
|
||||
""";
|
||||
AuthConfigException ex = assertThrows(AuthConfigException.class, () -> AuthConfigs.parse(json));
|
||||
assertTrue(ex.getMessage().contains("projectId"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateFails_whenBitanswerWithoutUrl() {
|
||||
String json =
|
||||
"""
|
||||
{"schemaVersion":1,"provider":"bitanswer","scenario":"school",\
|
||||
"bitanswer":{"url":""}}\
|
||||
""";
|
||||
assertThrows(AuthConfigException.class, () -> AuthConfigs.parse(json));
|
||||
}
|
||||
|
||||
@Test
|
||||
void roundTrip_toJson() throws Exception {
|
||||
String json = readClasspath("examples/config/school.bitanswer.json");
|
||||
AuthConfig c = AuthConfigs.parse(json);
|
||||
String out = AuthConfigs.toJson(c);
|
||||
AuthConfig again = AuthConfigs.parse(out);
|
||||
assertEquals(c.scenario(), again.scenario());
|
||||
assertEquals(c.bitanswerFeatureId("expression"), again.bitanswerFeatureId("expression"));
|
||||
}
|
||||
|
||||
private static String readClasspath(String path) throws Exception {
|
||||
try (InputStream in = AuthConfigsTest.class.getClassLoader().getResourceAsStream(path)) {
|
||||
assertNotNull(in, "missing classpath resource: " + path);
|
||||
return new String(in.readAllBytes(), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package cn.craftlabs.auth.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.networknt.schema.JsonSchema;
|
||||
import com.networknt.schema.JsonSchemaFactory;
|
||||
import com.networknt.schema.SpecVersion;
|
||||
import com.networknt.schema.ValidationMessage;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* BP-10 / I5:{@code examples/config/*.json} 与仓库根 {@code schemas/craftlabs-auth-config.schema.json} 一致。
|
||||
*/
|
||||
class ExamplesConfigSchemaValidationTest {
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
@Test
|
||||
void allExampleConfigsValidateAgainstSchema() throws Exception {
|
||||
Path repoRoot = findRepoRoot();
|
||||
Path schemaPath = repoRoot.resolve("schemas/craftlabs-auth-config.schema.json");
|
||||
Path examplesDir = repoRoot.resolve("examples/config");
|
||||
assertTrue(Files.isRegularFile(schemaPath), "schema missing: " + schemaPath);
|
||||
assertTrue(Files.isDirectory(examplesDir), "examples dir missing: " + examplesDir);
|
||||
|
||||
JsonNode schemaNode = MAPPER.readTree(schemaPath.toFile());
|
||||
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012);
|
||||
JsonSchema schema = factory.getSchema(schemaNode);
|
||||
|
||||
try (Stream<Path> stream = Files.list(examplesDir)) {
|
||||
stream.filter(p -> p.toString().endsWith(".json")).forEach(jsonFile -> {
|
||||
try {
|
||||
JsonNode instance = MAPPER.readTree(jsonFile.toFile());
|
||||
Set<ValidationMessage> errors = schema.validate(instance);
|
||||
assertTrue(
|
||||
errors.isEmpty(),
|
||||
() -> jsonFile.getFileName() + ": " + errors);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(jsonFile.toString(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自 {@code user.dir} 向上查找含 {@code schemas/craftlabs-auth-config.schema.json} 的目录(兼容模块目录或仓库根执行)。
|
||||
*/
|
||||
static Path findRepoRoot() {
|
||||
Path p = Path.of(System.getProperty("user.dir", ".")).toAbsolutePath().normalize();
|
||||
for (int i = 0; i < 8 && p != null; i++) {
|
||||
Path candidate = p.resolve("schemas/craftlabs-auth-config.schema.json");
|
||||
if (Files.isRegularFile(candidate)) {
|
||||
return p;
|
||||
}
|
||||
p = p.getParent();
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"Could not find repo root (schemas/craftlabs-auth-config.schema.json) from user.dir="
|
||||
+ System.getProperty("user.dir"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"provider": "bitanswer",
|
||||
"scenario": "floating",
|
||||
"bitanswer": {
|
||||
"url": "https://cloud.bitanswer.example/e3",
|
||||
"loginMode": "REMOTE"
|
||||
},
|
||||
"features": {
|
||||
"face": { "bitanswerFeatureId": 301 }
|
||||
},
|
||||
"floating": {
|
||||
"projectId": "migrant-flow-prj-2026-001",
|
||||
"projectName": "某市流动人口人像核验",
|
||||
"contractRef": "PO-2026-8848"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"provider": "bitanswer",
|
||||
"scenario": "school",
|
||||
"bitanswer": {
|
||||
"url": "https://cloud.bitanswer.example/e3",
|
||||
"loginMode": "AUTO",
|
||||
"sn": ""
|
||||
},
|
||||
"features": {
|
||||
"face": { "bitanswerFeatureId": 201 },
|
||||
"expression": { "bitanswerFeatureId": 202 }
|
||||
},
|
||||
"school": {
|
||||
"edgeDeviceId": "classroom-gate-01",
|
||||
"tenantId": "school-district-demo"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"provider": "bitanswer",
|
||||
"scenario": "wharf",
|
||||
"bitanswer": {
|
||||
"url": "bit://license.example.com:8273",
|
||||
"loginMode": "AUTO",
|
||||
"rootPath": "/var/lib/craftlabs/bitanswer"
|
||||
},
|
||||
"features": {
|
||||
"container_number_detect": { "bitanswerFeatureId": 101 },
|
||||
"container_number_recognize": { "bitanswerFeatureId": 102 },
|
||||
"iso_detect": { "bitanswerFeatureId": 103 },
|
||||
"iso_recognize": { "bitanswerFeatureId": 104 }
|
||||
},
|
||||
"wharf": {
|
||||
"topology": "group",
|
||||
"groupServiceUrl": "bit://license.example.com:8273",
|
||||
"notes": "边设备集中连集团服务;特征项与控制台产品一致后替换 id。"
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,8 @@
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<!-- 测试模块不发布;跳过 GPG 以免生成多余 .asc -->
|
||||
<gpg.skip>true</gpg.skip>
|
||||
<native.library.path>${project.basedir}/../../native/build</native.library.path>
|
||||
</properties>
|
||||
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.release>17</maven.compiler.release>
|
||||
<junit.version>5.10.2</junit.version>
|
||||
<jackson.version>2.17.2</jackson.version>
|
||||
<json-schema-validator.version>1.5.7</json-schema-validator.version>
|
||||
<!-- 默认跳过 GPG;发布签名:mvn -Prelease-sign verify(见 RELEASING.md) -->
|
||||
<gpg.skip>true</gpg.skip>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -36,6 +40,17 @@
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.networknt</groupId>
|
||||
<artifactId>json-schema-validator</artifactId>
|
||||
<version>${json-schema-validator.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@@ -52,7 +67,39 @@
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.2.5</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>3.2.7</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<!-- 对发布 JAR 做 GPG 分离签名(.asc);显式 -Prelease-sign 时启用 -->
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release-sign</id>
|
||||
<properties>
|
||||
<gpg.skip>false</gpg.skip>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-release-artifacts</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
* FFI / Python(ctypes、cffi)说明
|
||||
* ----------------------------------
|
||||
* - 所有 `const char*` 均为 **UTF-8** 编码、以 `\0` 结尾。
|
||||
* - `config_json`:UTF-8 JSON,语义与仓库 `schemas/craftlabs-auth-config.schema.json` 及 `examples/config/`
|
||||
* 一致;Java 侧可先经 `cn.craftlabs.auth.config.AuthConfigs` 校验后再序列化传入。
|
||||
* - `AuthHandle`:不透明指针,仅由本库函数产生与销毁(`auth_initialize` / `auth_destroy`)。
|
||||
* - `AuthResult`、`LicenseInfo` 使用 `stdint` 定宽字段,避免 `time_t`/`int` 宽度随平台变化导致 Python 侧 Structure 布局错误。
|
||||
* - `AuthResult.message`:指向 **由本库管理的静态或内部只读缓冲区**,调用方不得 `free`;在任意后续对本库的再次调用之后视为可能失效(与其它 FFI 语言惯例一致)。
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://craftlabs.cn/schemas/craftlabs-auth-config.json",
|
||||
"title": "CraftLabs Auth — initialize(config_json)",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["schemaVersion", "provider", "scenario"],
|
||||
"properties": {
|
||||
"schemaVersion": {
|
||||
"type": "integer",
|
||||
"const": 1,
|
||||
"description": "配置格式版本;与解析器 AuthConfigs.SCHEMA_VERSION 对齐。"
|
||||
},
|
||||
"provider": {
|
||||
"type": "string",
|
||||
"enum": ["bitanswer", "selfhosted"],
|
||||
"description": "后端实现:比特安索 native 或自研 HTTP。"
|
||||
},
|
||||
"scenario": {
|
||||
"type": "string",
|
||||
"enum": ["wharf", "school", "floating"],
|
||||
"description": "业务场景:码头集中授权、学校按边设备、流动人口按项目。"
|
||||
},
|
||||
"bitanswer": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "provider=bitanswer 时由校验器要求非空且含 url。",
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "Bit_Login szURL:云 http(s)://、集团 bit://、本地 lic:// 等,参见比特文档。"
|
||||
},
|
||||
"loginMode": {
|
||||
"type": "string",
|
||||
"description": "与 Bitanswer Java LoginMode 名称一致,如 AUTO、REMOTE、LOCAL。"
|
||||
},
|
||||
"rootPath": {
|
||||
"type": "string",
|
||||
"description": "可选;对应 Bit_SetRootPath。"
|
||||
},
|
||||
"sn": {
|
||||
"type": "string",
|
||||
"description": "可选;若激活前即固定 SN 可放此处,否则走 activate(licenseKey)。"
|
||||
},
|
||||
"applicationData": {
|
||||
"type": "string",
|
||||
"description": "随产品绑定的 application_data,若不由库内编译常量承担。"
|
||||
}
|
||||
}
|
||||
},
|
||||
"selfhosted": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "provider=selfhosted 时由校验器要求非空且含 baseUrl。",
|
||||
"properties": {
|
||||
"baseUrl": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "自研授权服务根 URL。"
|
||||
},
|
||||
"tenantKey": {
|
||||
"type": "string",
|
||||
"description": "可选;租户或调用方标识。"
|
||||
}
|
||||
}
|
||||
},
|
||||
"features": {
|
||||
"type": "object",
|
||||
"description": "逻辑特性键 → 比特特征项 id 或名称,供 hasFeature 映射。",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"bitanswerFeatureId": { "type": "integer" },
|
||||
"bitanswerFeatureName": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"wharf": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "scenario=wharf 时建议填写。",
|
||||
"properties": {
|
||||
"topology": {
|
||||
"type": "string",
|
||||
"enum": ["cloud", "group", "local_float"],
|
||||
"description": "云授权、集团授权或单机浮动等拓扑提示。"
|
||||
},
|
||||
"groupServiceUrl": {
|
||||
"type": "string",
|
||||
"description": "topology=group 时 bit://host:port。"
|
||||
},
|
||||
"notes": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"school": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "scenario=school 时建议填写。",
|
||||
"properties": {
|
||||
"edgeDeviceId": {
|
||||
"type": "string",
|
||||
"description": "边设备实例标识,用于运营侧对账;不参与比特 API 则仅作遥测/日志。"
|
||||
},
|
||||
"tenantId": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"floating": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "scenario=floating 时校验器要求 projectId。",
|
||||
"properties": {
|
||||
"projectId": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "项目维度授权锚点。"
|
||||
},
|
||||
"projectName": { "type": "string" },
|
||||
"contractRef": { "type": "string", "description": "合同或订单引用,可选。" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": { "properties": { "provider": { "const": "bitanswer" } } },
|
||||
"then": {
|
||||
"required": ["bitanswer"],
|
||||
"properties": {
|
||||
"bitanswer": {
|
||||
"type": "object",
|
||||
"required": ["url"],
|
||||
"properties": { "url": { "type": "string", "minLength": 1 } }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": { "properties": { "provider": { "const": "selfhosted" } } },
|
||||
"then": {
|
||||
"required": ["selfhosted"],
|
||||
"properties": {
|
||||
"selfhosted": {
|
||||
"type": "object",
|
||||
"required": ["baseUrl"],
|
||||
"properties": { "baseUrl": { "type": "string", "minLength": 1 } }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": { "properties": { "scenario": { "const": "floating" } } },
|
||||
"then": {
|
||||
"required": ["floating"],
|
||||
"properties": {
|
||||
"floating": {
|
||||
"type": "object",
|
||||
"required": ["projectId"],
|
||||
"properties": { "projectId": { "type": "string", "minLength": 1 } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Executable
+126
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env bash
|
||||
# 生成对外发布用 SHA256SUMS(相对仓库根路径,便于客户执行 sha256sum -c)。
|
||||
# 用法见 java/RELEASING.md
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
OUTPUT="${ROOT}/dist/sdk-release"
|
||||
RUN_MVN="package"
|
||||
SKIP_TESTS="-DskipTests"
|
||||
NATIVE_PATH=""
|
||||
SIGN="${SIGN:-0}"
|
||||
|
||||
usage() {
|
||||
sed -n '2,20p' "$0" | head -5
|
||||
echo "用法: $0 [--output DIR] [--verify] [--native-path DIR] [--no-mvn]"
|
||||
echo " --output DIR 输出目录(默认 dist/sdk-release)"
|
||||
echo " --verify 执行 mvn verify(默认为 package -DskipTests)"
|
||||
echo " --native-path DIR 额外哈希该目录下 .so/.dylib/.dll"
|
||||
echo " --no-mvn 不执行 Maven(假定已 package)"
|
||||
echo "环境变量 SIGN=1 且已配置 gpg 时,生成 SHA256SUMS.asc"
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--output)
|
||||
OUTPUT="$2"
|
||||
shift 2
|
||||
;;
|
||||
--verify)
|
||||
RUN_MVN="verify"
|
||||
SKIP_TESTS=""
|
||||
shift
|
||||
;;
|
||||
--native-path)
|
||||
NATIVE_PATH="$2"
|
||||
shift 2
|
||||
;;
|
||||
--no-mvn)
|
||||
NO_MVN=1
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "未知参数: $1" >&2
|
||||
usage >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
mkdir -p "$OUTPUT"
|
||||
|
||||
if [[ -z "${NO_MVN:-}" ]]; then
|
||||
if [[ -n "$SKIP_TESTS" ]]; then
|
||||
(cd "$ROOT/java" && mvn -q $SKIP_TESTS "$RUN_MVN")
|
||||
else
|
||||
(cd "$ROOT/java" && mvn -q "$RUN_MVN")
|
||||
fi
|
||||
fi
|
||||
|
||||
SUMFILE="${OUTPUT}/SHA256SUMS"
|
||||
: >"$SUMFILE"
|
||||
|
||||
add_hash() {
|
||||
local file="$1"
|
||||
local rel="$2"
|
||||
local h
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
h=$(sha256sum "$file" | awk '{print $1}')
|
||||
else
|
||||
h=$(shasum -a 256 "$file" | awk '{print $1}')
|
||||
fi
|
||||
echo "$h $rel" >>"$SUMFILE"
|
||||
}
|
||||
|
||||
for mod in craftlabs-auth-core craftlabs-auth-bitanswer craftlabs-auth-selfhosted; do
|
||||
dir="$ROOT/java/$mod/target"
|
||||
[[ -d "$dir" ]] || {
|
||||
echo "缺少目录: $dir(请先 mvn package)" >&2
|
||||
exit 1
|
||||
}
|
||||
shopt -s nullglob
|
||||
for f in "$dir"/*.jar; do
|
||||
bn=$(basename "$f")
|
||||
[[ "$bn" == *-sources.jar ]] && continue
|
||||
[[ "$bn" == *-javadoc.jar ]] && continue
|
||||
add_hash "$f" "java/$mod/target/$bn"
|
||||
done
|
||||
shopt -u nullglob
|
||||
done
|
||||
|
||||
if [[ -f "$ROOT/schemas/craftlabs-auth-config.schema.json" ]]; then
|
||||
add_hash "$ROOT/schemas/craftlabs-auth-config.schema.json" "schemas/craftlabs-auth-config.schema.json"
|
||||
fi
|
||||
|
||||
if [[ -n "$NATIVE_PATH" ]]; then
|
||||
[[ -d "$NATIVE_PATH" ]] || {
|
||||
echo "无效 --native-path: $NATIVE_PATH" >&2
|
||||
exit 1
|
||||
}
|
||||
find "$NATIVE_PATH" -type f \( -name '*.so' -o -name '*.dylib' -o -name '*.dll' \) | while IFS= read -r nf; do
|
||||
rel="${nf#$ROOT/}"
|
||||
add_hash "$nf" "$rel"
|
||||
done
|
||||
fi
|
||||
|
||||
{
|
||||
echo "repo=$(basename "$ROOT")"
|
||||
git -C "$ROOT" rev-parse HEAD 2>/dev/null || echo "git=n/a"
|
||||
date -u +"%Y-%m-%dT%H:%M:%SZ"
|
||||
} >"${OUTPUT}/RELEASE-MANIFEST.txt"
|
||||
|
||||
echo "已写入: $SUMFILE"
|
||||
wc -l "$SUMFILE"
|
||||
|
||||
if [[ "$SIGN" == "1" ]] && command -v gpg >/dev/null 2>&1; then
|
||||
gpg --batch --yes --armor --detach-sign --output "${SUMFILE}.asc" "$SUMFILE"
|
||||
echo "已写入: ${SUMFILE}.asc"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "校验(在仓库根目录执行):"
|
||||
echo " cd \"$ROOT\" && sha256sum -c \"${SUMFILE#$ROOT/}\""
|
||||
Reference in New Issue
Block a user