diff --git a/nl-verify-check-sdk/pom.xml b/nl-verify-check-sdk/pom.xml index 4220d42..a408d03 100644 --- a/nl-verify-check-sdk/pom.xml +++ b/nl-verify-check-sdk/pom.xml @@ -10,6 +10,7 @@ nl-verify-check-sdk + 1.1-SNAPSHOT 8 diff --git a/nl-verify-check-sdk/src/main/java/org/nl/api/LicenseController.java b/nl-verify-check-sdk/src/main/java/org/nl/api/LicenseController.java index a306e2e..9cf1d68 100644 --- a/nl-verify-check-sdk/src/main/java/org/nl/api/LicenseController.java +++ b/nl-verify-check-sdk/src/main/java/org/nl/api/LicenseController.java @@ -3,6 +3,7 @@ package org.nl.api; import lombok.AllArgsConstructor; import org.nl.core.LicenseResult; import org.nl.core.LicenseVerifier; +import org.nl.util.MachineCodeUtil; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -32,4 +33,10 @@ public class LicenseController { } return new ResponseEntity<>(verify, HttpStatus.OK); } + + @GetMapping("/machine-code") + public ResponseEntity getMachineCode() { + String machineCode = MachineCodeUtil.getMachineCode(); + return new ResponseEntity<>(machineCode, HttpStatus.OK); + } } diff --git a/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseAutoConfiguration.java b/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseAutoConfiguration.java index 2f0e08f..6488845 100644 --- a/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseAutoConfiguration.java +++ b/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseAutoConfiguration.java @@ -42,7 +42,8 @@ public class LicenseAutoConfiguration implements WebMvcConfigurer { public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authInterceptor) .addPathPatterns("/**") - .excludePathPatterns("/auth/login", "/auth/code", "/auth/logout", "/auth/info", "/api/verify/activity"); + .excludePathPatterns("/auth/login", "/auth/code", "/auth/logout", "/auth/info", + "/api/verify/activity", "/api/verify/machine-code"); } } diff --git a/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseResult.java b/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseResult.java index add9845..82a9577 100644 --- a/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseResult.java +++ b/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseResult.java @@ -14,13 +14,16 @@ public class LicenseResult { private Boolean result; /** 附加信息 */ private String message; - /** 证书key */ + /** 证书 key */ private String content; + /** 机器码 */ + private String machineCode; public static LicenseResult requestResult(Boolean result, String message, String content) { return LicenseResult.builder() .message(message) .result(result) .content(content) + .machineCode(null) .build(); } public static LicenseResult requestOk(String message, String content) { @@ -28,6 +31,7 @@ public class LicenseResult { .message(message) .result(true) .content(content) + .machineCode(null) .build(); } } diff --git a/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseVerifier.java b/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseVerifier.java index 6d3074a..ca99359 100644 --- a/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseVerifier.java +++ b/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseVerifier.java @@ -1,5 +1,6 @@ package org.nl.core; +import org.nl.util.MachineCodeUtil; import org.nl.util.RSAUtil; import java.io.IOException; @@ -33,7 +34,18 @@ public class LicenseVerifier { return LicenseResult.requestResult(false, "请输入授权码", null); } try { - String expirationStr = rsaUtil.decrypt(authCode); + String decrypted = rsaUtil.decrypt(authCode); + String[] parts = decrypted.split("\\|"); + String expirationStr = parts[0]; + String machineFingerprint = parts.length > 1 ? parts[1] : null; + + if (machineFingerprint != null && !machineFingerprint.isEmpty()) { + String currentMachineCode = MachineCodeUtil.getMachineCode(); + if (!currentMachineCode.equals(machineFingerprint)) { + return LicenseResult.requestResult(false, "授权码与当前机器不匹配", authCode); + } + } + if ("-1".equals(expirationStr)) { return LicenseResult.requestOk("永久授权", authCode); } diff --git a/nl-verify-check-sdk/src/main/java/org/nl/util/MachineCodeUtil.java b/nl-verify-check-sdk/src/main/java/org/nl/util/MachineCodeUtil.java new file mode 100644 index 0000000..46d9b39 --- /dev/null +++ b/nl-verify-check-sdk/src/main/java/org/nl/util/MachineCodeUtil.java @@ -0,0 +1,65 @@ +package org.nl.util; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; + +/** + * 机器指纹工具类,基于 MAC 地址 + 主机名生成唯一机器标识。 + * @Author: zhaoyf + * @Date: 2026/5/25 + */ +public class MachineCodeUtil { + + private static volatile String cachedMachineCode; + + public static String getMachineCode() { + if (cachedMachineCode != null) { + return cachedMachineCode; + } + synchronized (MachineCodeUtil.class) { + if (cachedMachineCode != null) { + return cachedMachineCode; + } + try { + + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + List macs = new ArrayList<>(); + while (interfaces.hasMoreElements()) { + NetworkInterface ni = interfaces.nextElement(); + if (ni.isLoopback() || ni.isVirtual() || !ni.isUp()) { + continue; + } + byte[] mac = ni.getHardwareAddress(); + if (mac != null) { + StringBuilder sb = new StringBuilder(); + for (byte b : mac) { + sb.append(String.format("%02X", b)); + } + macs.add(sb.toString()); + } + } + Collections.sort(macs); + + String combined = String.join("|", macs); + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] hash = md.digest(combined.getBytes("UTF-8")); + + StringBuilder hex = new StringBuilder(); + for (byte b : hash) { + hex.append(String.format("%02x", b)); + } + cachedMachineCode = hex.toString(); + } catch (Exception e) { + cachedMachineCode = "UNKNOWN"; + } + return cachedMachineCode; + } + } + +} \ No newline at end of file diff --git a/nl-verify-check-test/pom.xml b/nl-verify-check-test/pom.xml index ddf8c5c..7ef690e 100644 --- a/nl-verify-check-test/pom.xml +++ b/nl-verify-check-test/pom.xml @@ -21,8 +21,41 @@ org.nl nl-verify-check-sdk - 1.0 + 1.1-SNAPSHOT + + + + org.springframework.boot + spring-boot-maven-plugin + + + com.gitee.lcm742320521 + classfinal-maven-plugin + 1.4.1 + + + nl2024 + + org.nl + + application.yml,application-dev.yml,application-prod.yml + + org.nl.**.domain.**,org.nl.Application + + + + + + package + + classFinal + + + + + + diff --git a/nl-verify-check-test/src/main/resources/private_key.txt b/nl-verify-check-test/src/main/resources/private_key.txt index 7ae8272..12c061e 100644 --- a/nl-verify-check-test/src/main/resources/private_key.txt +++ b/nl-verify-check-test/src/main/resources/private_key.txt @@ -1 +1 @@ -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 \ No newline at end of file