Java 接入指南

使用 JDK 标准库 HttpClient 与 Ed25519 完成激活、验签与停用。

本指南覆盖完整闭环:激活 → 本地保存 → 启动校验 → 停用。示例假设你已经拿到工作区与一份授权码。

需要 JDK 15+(Ed25519 支持)。示例只依赖标准库。

1. 激活

LicenseClient.java
import java.net.URI;
import java.net.http.*;
import java.nio.charset.StandardCharsets;

static final String BASE = "https://keygate.unionuser.com";

static String activate(String licenseKey, String deviceId) throws Exception {
    String json = "{\"license_key\":\"" + licenseKey
        + "\",\"identifier\":\"" + deviceId
        + "\",\"identifier_type\":\"device\"}";

    HttpRequest req = HttpRequest.newBuilder(URI.create(BASE + "/api/v1/license/activate"))
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.ofString(json, StandardCharsets.UTF_8))
        .build();

    HttpResponse<String> res = HttpClient.newHttpClient()
        .send(req, HttpResponse.BodyHandlers.ofString());
    if (res.statusCode() != 200) throw new IllegalStateException("activate " + res.statusCode());
    // Parse token from the JSON response (use your JSON library here).
    return res.body();
}

2. 离线验签

Verify.java
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HexFormat;

static final byte[] SPKI_PREFIX = HexFormat.of()
    .parseHex("302a300506032b6570032100");
static final byte[] RAW_PUBLIC = HexFormat.of()
    .parseHex("bf17435ee7b937b3592808941683c21d37c4e124d95d4e8fdd86fe775dd23b11");

static boolean verifyToken(String token, String deviceId) throws Exception {
    String[] parts = token.split("\\.");
    String payloadB64 = parts[0];
    byte[] signature = b64url(parts[1]);

    byte[] spki = new byte[SPKI_PREFIX.length + RAW_PUBLIC.length];
    System.arraycopy(SPKI_PREFIX, 0, spki, 0, SPKI_PREFIX.length);
    System.arraycopy(RAW_PUBLIC, 0, spki, SPKI_PREFIX.length, RAW_PUBLIC.length);

    PublicKey key = KeyFactory.getInstance("Ed25519")
        .generatePublic(new X509EncodedKeySpec(spki));

    Signature sig = Signature.getInstance("Ed25519");
    sig.initVerify(key);
    sig.update(payloadB64.getBytes(StandardCharsets.US_ASCII));
    if (!sig.verify(signature)) return false;

    // Decode payload and compare did / exp with your JSON parser.
    return true;
}

static byte[] b64url(String value) {
    String padded = value;
    while (padded.length() % 4 != 0) padded += "=";
    return Base64.getUrlDecoder().decode(padded);
}

3. 停用

Deactivate.java
HttpRequest req = HttpRequest.newBuilder(URI.create(BASE + "/api/v1/license/deactivate"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(json))
    .build();
HttpResponse<String> res = HttpClient.newHttpClient()
    .send(req, HttpResponse.BodyHandlers.ofString());

桌面集成提示

  • 用 Jackson 或 Gson 解析响应和 payload,避免手写字符串拼接。
  • Windows 可用 reg query 读取 MachineGuid;Java 侧也可用 JNA(需额外依赖)。
  • 把 token 存在用户目录(如 %APPDATA%),不要写注册表明文的私密内容。