2
0

feat: 支持激活码license

This commit is contained in:
caiyuchao
2025-04-17 20:54:30 +08:00
parent 73a25e95c7
commit cb24deceb0
5 changed files with 167 additions and 52 deletions

View File

@@ -70,4 +70,29 @@ public class LicenseCheckModel implements Serializable {
", mainBoardSerial='" + mainBoardSerial + '\'' +
'}';
}
public String toJsonString() {
StringBuilder jsonBuilder = new StringBuilder();
jsonBuilder.append("{");
// jsonBuilder.append("\"ipAddress\": [");
// for (String ip : ipAddress) {
// jsonBuilder.append("\"").append(ip).append("\", ");
// }
// jsonBuilder.deleteCharAt(jsonBuilder.length() - 1);
// jsonBuilder.deleteCharAt(jsonBuilder.length() - 1);
// jsonBuilder.append("], ");
// jsonBuilder.append("\"macAddress\": [");
// for (String mac : macAddress) {
// jsonBuilder.append("\"").append(mac).append("\", ");
// }
// jsonBuilder.deleteCharAt(jsonBuilder.length() - 1);
// jsonBuilder.deleteCharAt(jsonBuilder.length() - 1);
// jsonBuilder.append("], ");
jsonBuilder.append("\"cpuSerial\": \"").append(cpuSerial).append("\", ");
jsonBuilder.append("\"mainBoardSerial\": \"").append(mainBoardSerial).append("\"");
// jsonBuilder.append("\"registerAmount\": \"").append(registerAmount).append("\"");
jsonBuilder.append("}");
return jsonBuilder.toString();
}
}

View File

@@ -1,6 +1,7 @@
package org.wfc.common.license.runner;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -8,13 +9,19 @@ import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.wfc.common.license.LicenseVerify;
import org.wfc.common.license.domain.LicenseCheckModel;
import org.wfc.common.license.domain.LicenseVerifyParam;
import org.wfc.common.license.serverinfo.AbstractServerInfos;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@@ -31,6 +38,8 @@ public class LicenseCheckRunner implements ApplicationRunner {
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> scheduledFuture;
private static final String key = "wfcwanfiAdmin6666";
// 启动定时任务
public void startTimer() {
@@ -114,6 +123,73 @@ public class LicenseCheckRunner implements ApplicationRunner {
log.info("++++++++ 证书安装结束 ++++++++");
}
private void generate() {
try {
LicenseCheckModel serverInfos = AbstractServerInfos.getServer("").getServerInfos();
//对象序列化为json
String jsonString = serverInfos.toJsonString();
System.out.println("原始数据 = " + jsonString);
//加密
String encryptedJson = encrypt(jsonString);
System.out.println("加密后 = " + encryptedJson);
// 解密
String decryptedJson = decrypt(encryptedJson);
System.out.println("解密后 = " + decryptedJson);
// 比较解密后的字符串与原始字符串
if (jsonString.equals(decryptedJson)) {
} else {
log.info("解密后的字符串与原始字符串不同");
}
// 断言
assert jsonString.equals(decryptedJson) : "解密后的字符串与原始字符串不匹配";
// 反序列化为对象
ObjectMapper mapper = new ObjectMapper();
LicenseCheckModel licenseParam = null;
licenseParam = mapper.readValue(decryptedJson, LicenseCheckModel.class);
// 标记为null的字段需要特殊处理
// if ("null".equals(licenseParam.getRegisterAmount())) {
// licenseParam.setRegisterAmount(null);
// }
FileWriter writer = new FileWriter(licenseProperties.getCodePath());
writer.write(encryptedJson);
writer.close();
log.info("licenseParam {}", licenseParam);
} catch (Exception e) {
log.error("生成激活码失败", e);
}
}
private String encrypt(String json) throws Exception {
byte[] keyBytes = key.getBytes();
MessageDigest sha = MessageDigest.getInstance("SHA-256");
keyBytes = sha.digest(keyBytes);
keyBytes = java.util.Arrays.copyOf(keyBytes, 16);
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedBytes = cipher.doFinal(json.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}
private String decrypt(String encryptedJson) throws Exception {
byte[] keyBytes = key.getBytes();
MessageDigest sha = MessageDigest.getInstance("SHA-256");
keyBytes = sha.digest(keyBytes);
keyBytes = java.util.Arrays.copyOf(keyBytes, 16);
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedJson);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes);
}
/**
* <p>获取文件的md5</p>
*/
@@ -159,6 +235,7 @@ public class LicenseCheckRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
generate();
install();
startTimer();
}

View File

@@ -32,6 +32,11 @@ public class LicenseProperties {
*/
private String licensePath = "/opt/wfc/license/license.lic";
/**
* 激活码生成路径
*/
private String codePath = "/opt/wfc/license/activation_code.txt";
/**
* 密钥库存储路径
*/

View File

@@ -20,17 +20,18 @@ public abstract class AbstractServerInfos {
* 组装需要额外校验的License参数
*
* @return demo.LicenseCheckModel
* @since 1.0.0
*/
public LicenseCheckModel getServerInfos() {
LicenseCheckModel result = new LicenseCheckModel();
try {
result.setIpAddress(this.getIpAddress());
result.setMacAddress(this.getMacAddress());
// result.setIpAddress(this.getIpAddress());
// result.setMacAddress(this.getMacAddress());
result.setCpuSerial(this.getCPUSerial());
result.setMainBoardSerial(this.getMainBoardSerial());
} catch (Exception e) {
log.error("获取服务器硬件信息失败 {}", e.getMessage());
log.error("获取服务器硬件信息失败", e);
}
return result;
@@ -86,7 +87,6 @@ public abstract class AbstractServerInfos {
}
}
}
return result;
}
@@ -100,12 +100,10 @@ public abstract class AbstractServerInfos {
try {
byte[] mac = NetworkInterface.getByInetAddress(inetAddr).getHardwareAddress();
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < mac.length; i++) {
if (i != 0) {
stringBuffer.append("-");
}
//将十六进制byte转化为字符串
String temp = Integer.toHexString(mac[i] & 0xff);
if (temp.length() == 1) {
@@ -114,14 +112,33 @@ public abstract class AbstractServerInfos {
stringBuffer.append(temp);
}
}
return stringBuffer.toString().toUpperCase();
} catch (SocketException e) {
e.printStackTrace();
log.error("获取某个网络接口的Mac地址异常", e.getMessage());
}
return null;
}
/**
* <p>获取服务器信息</p>
*
* @param osName 系统类型
* @return AGxServerInfos 服务信息
*/
public static AbstractServerInfos getServer(String osName) {
if ("".equals(osName) || osName == null) {
osName = System.getProperty("os.name").toLowerCase();
}
AbstractServerInfos abstractServerInfos;
// 根据不同操作系统类型选择不同的数据获取方法
if (osName.startsWith("windows")) {
abstractServerInfos = new WindowsServerInfos();
} else if (osName.startsWith("linux")) {
abstractServerInfos = new LinuxServerInfos();
} else {// 其他服务器类型
abstractServerInfos = new LinuxServerInfos();
}
return abstractServerInfos;
}
}

View File

@@ -1,7 +1,8 @@
package org.wfc.common.license.serverinfo;
import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.util.List;
@@ -12,9 +13,6 @@ import java.util.stream.Collectors;
*/
public class LinuxServerInfos extends AbstractServerInfos {
private final String[] CPU_SHELL = {"/bin/bash", "-c", "dmidecode -t processor | grep 'ID' | awk -F ':' '{print $2}' | head -n 1"};
private final String[] MAIN_BOARD_SHELL = {"/bin/bash", "-c", "dmidecode | grep 'Serial Number' | awk -F ':' '{print $2}' | head -n 1"};
@Override
protected List<String> getIpAddress() throws Exception {
List<String> result = null;
@@ -46,50 +44,43 @@ public class LinuxServerInfos extends AbstractServerInfos {
@Override
protected String getCPUSerial() throws Exception {
String result = "";
String CPU_ID_CMD = "dmidecode";
BufferedReader bufferedReader = null;
Process p = null;
try {
p = Runtime.getRuntime().exec(new String[]{"sh", "-c", CPU_ID_CMD});// 管道
bufferedReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
int index = -1;
while ((line = bufferedReader.readLine()) != null) {
// 寻找标示字符串[hwaddr]
index = line.toLowerCase().indexOf("uuid");
if (index >= 0) {// 找到了
// 取出mac地址并去除2边空格
result = line.substring(index + "uuid".length() + 1).trim();
break;
//序列号
String serialNumber = "";
//使用dmidecode命令获取CPU序列号
String[] shell = {"/bin/bash", "-c", "dmidecode -t processor | grep 'ID' | awk -F ':' '{print $2}' | head -n 1"};
Process process = Runtime.getRuntime().exec(shell);
process.getOutputStream().close();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = reader.readLine().trim();
if (StringUtils.isNotBlank(line)) {
serialNumber = line;
}
}
} catch (IOException e) {
System.out.println("获取cpu硬件信息失败 " + e);
}
return result.trim();
// return GxServerSerialHelper.getLinuxSerial(CPU_SHELL);
reader.close();
return serialNumber;
}
@Override
protected String getMainBoardSerial() throws Exception {
String result = "";
String maniBord_cmd = "dmidecode | grep 'Serial Number' | awk '{print $3}' | tail -1";
Process p;
try {
p = Runtime.getRuntime().exec(new String[]{"sh", "-c", maniBord_cmd});// 管道
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
result += line;
break;
}
br.close();
} catch (IOException e) {
System.out.println("获取主板信息错误" + e);
}
return result;
// return GxServerSerialHelper.getLinuxSerial(MAIN_BOARD_SHELL);
//序列号
String serialNumber = "";
//使用dmidecode命令获取主板序列号
String[] shell = {"/bin/bash", "-c", "dmidecode | grep 'Serial Number' | awk -F ':' '{print $2}' | head -n 1"};
Process process = Runtime.getRuntime().exec(shell);
process.getOutputStream().close();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = reader.readLine().trim();
if (StringUtils.isNotBlank(line)) {
serialNumber = line;
}
reader.close();
return serialNumber;
}
}