feat:授权码SDK版本迭代,新增设备机器码校验

This commit is contained in:
zhaoyf
2026-05-27 17:18:34 +08:00
parent 3939d6aeb1
commit be46596967
8 changed files with 128 additions and 5 deletions

View File

@@ -10,6 +10,7 @@
</parent>
<artifactId>nl-verify-check-sdk</artifactId>
<version>1.1-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>

View File

@@ -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<Object> getMachineCode() {
String machineCode = MachineCodeUtil.getMachineCode();
return new ResponseEntity<>(machineCode, HttpStatus.OK);
}
}

View File

@@ -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");
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -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<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
List<String> 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;
}
}
}

View File

@@ -21,8 +21,41 @@
<dependency>
<groupId>org.nl</groupId>
<artifactId>nl-verify-check-sdk</artifactId>
<version>1.0</version>
<version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.gitee.lcm742320521</groupId>
<artifactId>classfinal-maven-plugin</artifactId>
<version>1.4.1</version>
<configuration>
<!-- 必填:加密密码,请务必修改为强密码并妥善保管 -->
<password>nl2024</password>
<!-- 需要加密的包名(支持多个,逗号分隔) -->
<packages>org.nl</packages>
<!-- 需要加密的配置文件 -->
<cfgfiles>application.yml,application-dev.yml,application-prod.yml</cfgfiles>
<!-- 排除不需要加密的包如实体类、DTO -->
<excludes>org.nl.**.domain.**,org.nl.Application</excludes>
<!-- 可选绑定机器码使加密后的jar只能在此机器运行 -->
<!-- <code>目标机器的唯一标识码</code> -->
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>classFinal</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1 +1 @@
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