本指南覆盖完整闭环:激活 → 本地保存 → 启动校验 → 停用。示例假设你已经拿到工作区与一份授权码。
需要 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%),不要写注册表明文的私密内容。