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,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>
|
||||
Reference in New Issue
Block a user