package com.estate.expert.admin.utils;
|
|
import com.estate.expert.admin.enums.BizResultCode;
|
import com.estate.expert.common.exception.BizException;
|
import javax.crypto.Cipher;
|
import javax.crypto.spec.SecretKeySpec;
|
import java.nio.charset.StandardCharsets;
|
import java.security.MessageDigest;
|
import java.time.LocalDate;
|
import java.time.format.DateTimeFormatter;
|
import java.util.Base64;
|
import java.util.logging.Logger;
|
|
/**
|
* License验证工具类
|
* 用于系统license的加密、解密和验证
|
* 当license过期时,系统将停止运行
|
*/
|
public class License {
|
|
private static final Logger logger = Logger.getLogger(License.class.getName());
|
|
// 加密密钥(实际使用时应该从配置文件或环境变量中读取)
|
// AES密钥必须是16、24或32字节长度
|
private static final String SECRET_KEY = "EstateExpert2024Key32BytesForAES";
|
|
// License密钥(从配置文件读取)
|
private static String LICENSE_KEY;
|
|
// 加密算法
|
private static final String ALGORITHM = "AES";
|
|
// 日期格式
|
private static final String DATE_FORMAT = "yyyy-MM-dd";
|
|
// 系统启动时间
|
private static LocalDate systemStartDate;
|
|
// License过期日期
|
private static LocalDate licenseExpiryDate;
|
|
// License是否有效
|
private static boolean isLicenseValid = false;
|
|
// 静态初始化块,验证密钥
|
static {
|
if (!validateKey()) {
|
logger.severe("License系统初始化失败:密钥长度不正确");
|
}
|
}
|
|
/**
|
* 设置License密钥(从配置文件读取)
|
* @param licenseKey License密钥
|
*/
|
public static void setLicenseKey(String licenseKey) {
|
LICENSE_KEY = licenseKey;
|
// logger.info("License密钥已设置");
|
}
|
|
/**
|
* 初始化License验证(使用配置文件中的密钥)
|
* @throws BizException 当License验证失败时抛出
|
*/
|
public static void initializeLicenseFromConfig() {
|
if (LICENSE_KEY == null || LICENSE_KEY.trim().isEmpty()) {
|
logger.severe("License密钥未设置,系统无法启动");
|
throw new BizException(BizResultCode.LICENSE_NOT_CONFIGURED);
|
}
|
|
if (!initializeLicense(LICENSE_KEY)) {
|
throw new BizException(BizResultCode.LICENSE_VALIDATION_FAILED);
|
}
|
}
|
|
/**
|
* 验证密钥长度
|
* @return 密钥是否有效
|
*/
|
private static boolean validateKey() {
|
byte[] keyBytes = SECRET_KEY.getBytes(StandardCharsets.UTF_8);
|
if (keyBytes.length != 32) {
|
logger.severe("密钥长度不正确,需要32字节,当前: " + keyBytes.length + " 字节");
|
return false;
|
}
|
return true;
|
}
|
|
/**
|
* 初始化License验证
|
* @param encryptedLicense 加密的license字符串
|
* @return 是否初始化成功
|
*/
|
public static boolean initializeLicense(String encryptedLicense) {
|
try {
|
if (encryptedLicense == null || encryptedLicense.trim().isEmpty()) {
|
logger.severe("License字符串为空,系统无法启动");
|
BizResultCode.LICENSE_NOT_CONFIGURED.check(true);
|
return false;
|
}
|
|
// 解密license
|
String decryptedLicense = decrypt(encryptedLicense);
|
if (decryptedLicense == null) {
|
logger.severe("License解密失败,系统无法启动");
|
BizResultCode.LICENSE_VALIDATION_FAILED.check(true);
|
return false;
|
}
|
|
// 解析license信息
|
String[] licenseParts = decryptedLicense.split("\\|");
|
if (licenseParts.length != 3) {
|
logger.severe("License格式错误,系统无法启动");
|
BizResultCode.LICENSE_INVALID_FORMAT.check(true);
|
return false;
|
}
|
|
// 验证license签名
|
String licenseData = licenseParts[0] + "|" + licenseParts[1];
|
String signature = licenseParts[2];
|
if (!verifySignature(licenseData, signature)) {
|
logger.severe("License签名验证失败,系统无法启动");
|
BizResultCode.LICENSE_SIGNATURE_INVALID.check(true);
|
return false;
|
}
|
|
// 解析过期日期
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT);
|
licenseExpiryDate = LocalDate.parse(licenseParts[1], formatter);
|
systemStartDate = LocalDate.now();
|
|
// 检查license是否过期
|
if (isLicenseExpired()) {
|
logger.severe("License已过期,系统无法启动");
|
BizResultCode.LICENSE_EXPIRED.check(true);
|
return false;
|
}
|
|
isLicenseValid = true;
|
logger.info("启动验证,系统启动时间: " + systemStartDate +
|
", 过期时间: " + licenseExpiryDate);
|
return true;
|
} catch (BizException e) {
|
// 重新抛出BizException
|
throw e;
|
} catch (Exception e) {
|
logger.severe("License初始化失败: " + e.getMessage());
|
BizResultCode.LICENSE_VALIDATION_FAILED.check(true);
|
return false;
|
}
|
}
|
|
/**
|
* 检查License是否有效
|
* @return 是否有效
|
*/
|
public static boolean isLicenseValid() {
|
if (!isLicenseValid) {
|
return false;
|
}
|
|
// 检查是否过期
|
if (isLicenseExpired()) {
|
logger.severe("License已过期,系统将停止运行");
|
isLicenseValid = false;
|
return false;
|
}
|
|
return true;
|
}
|
|
/**
|
* 验证License有效性,如果无效则抛出异常
|
* @throws BizException 当License无效时抛出
|
*/
|
public static void validateLicense() {
|
if (!isLicenseValid()) {
|
throw new BizException(BizResultCode.LICENSE_EXPIRED);
|
}
|
}
|
|
/**
|
* 检查License是否过期
|
* @return 是否过期
|
*/
|
public static boolean isLicenseExpired() {
|
if (licenseExpiryDate == null) {
|
return true;
|
}
|
|
LocalDate currentDate = LocalDate.now();
|
return currentDate.isAfter(licenseExpiryDate);
|
}
|
|
/**
|
* 获取剩余天数
|
* @return 剩余天数,-1表示已过期
|
*/
|
public static long getRemainingDays() {
|
if (licenseExpiryDate == null) {
|
return -1;
|
}
|
|
LocalDate currentDate = LocalDate.now();
|
if (currentDate.isAfter(licenseExpiryDate)) {
|
return -1;
|
}
|
|
return java.time.temporal.ChronoUnit.DAYS.between(currentDate, licenseExpiryDate);
|
}
|
|
/**
|
* 生成License
|
* @param expiryDate 过期日期
|
* @return 加密的license字符串
|
*/
|
public static String generateLicense(LocalDate expiryDate) {
|
try {
|
String licenseData = "EstateExpert|" + expiryDate.format(DateTimeFormatter.ofPattern(DATE_FORMAT));
|
String signature = generateSignature(licenseData);
|
String fullLicense = licenseData + "|" + signature;
|
|
return encrypt(fullLicense);
|
} catch (Exception e) {
|
logger.severe("生成License失败: " + e.getMessage());
|
return null;
|
}
|
}
|
|
/**
|
* 加密字符串
|
* @param plainText 明文
|
* @return 加密后的字符串
|
*/
|
private static String encrypt(String plainText) {
|
try {
|
if (!validateKey()) {
|
return null;
|
}
|
|
SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM);
|
Cipher cipher = Cipher.getInstance(ALGORITHM);
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
|
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
|
return Base64.getEncoder().encodeToString(encryptedBytes);
|
} catch (Exception e) {
|
logger.severe("加密失败: " + e.getMessage());
|
return null;
|
}
|
}
|
|
/**
|
* 解密字符串
|
* @param encryptedText 加密的字符串
|
* @return 解密后的字符串
|
*/
|
private static String decrypt(String encryptedText) {
|
try {
|
if (!validateKey()) {
|
return null;
|
}
|
|
SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM);
|
Cipher cipher = Cipher.getInstance(ALGORITHM);
|
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
|
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
|
return new String(decryptedBytes, StandardCharsets.UTF_8);
|
} catch (Exception e) {
|
logger.severe("解密失败: " + e.getMessage());
|
return null;
|
}
|
}
|
|
/**
|
* 生成签名
|
* @param data 数据
|
* @return 签名
|
*/
|
private static String generateSignature(String data) {
|
try {
|
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
byte[] hash = digest.digest((data + SECRET_KEY).getBytes(StandardCharsets.UTF_8));
|
return Base64.getEncoder().encodeToString(hash);
|
} catch (Exception e) {
|
logger.severe("生成签名失败: " + e.getMessage());
|
return null;
|
}
|
}
|
|
/**
|
* 验证签名
|
* @param data 数据
|
* @param signature 签名
|
* @return 是否验证通过
|
*/
|
private static boolean verifySignature(String data, String signature) {
|
try {
|
String expectedSignature = generateSignature(data);
|
return expectedSignature != null && expectedSignature.equals(signature);
|
} catch (Exception e) {
|
logger.severe("验证签名失败: " + e.getMessage());
|
return false;
|
}
|
}
|
|
/**
|
* 强制停止系统
|
*/
|
public static void forceSystemShutdown() {
|
logger.severe("License验证失败,系统强制停止运行");
|
System.exit(1);
|
}
|
|
/**
|
* 获取License信息
|
* @return License信息字符串
|
*/
|
public static String getLicenseInfo() {
|
if (!isLicenseValid) {
|
return "License无效";
|
}
|
|
StringBuilder info = new StringBuilder();
|
info.append("系统启动时间: ").append(systemStartDate).append("\n");
|
info.append("License过期时间: ").append(licenseExpiryDate).append("\n");
|
info.append("剩余天数: ").append(getRemainingDays()).append("\n");
|
info.append("License状态: ").append(isLicenseExpired() ? "已过期" : "有效");
|
|
return info.toString();
|
}
|
|
/**
|
* 测试方法 - 生成测试License
|
* @param args 命令行参数
|
*/
|
public static void main(String[] args) {
|
try {
|
System.out.println("=== License验证系统测试 ===");
|
|
// 生成一个30天后过期的License
|
// LocalDate expiryDate = LocalDate.now().plusDays(-10);
|
LocalDate expiryDate = LocalDate.now().plusDays(199999);
|
String license = generateLicense(expiryDate);
|
|
if (license == null) {
|
System.err.println("生成License失败");
|
return;
|
}
|
|
System.out.println("生成的License: " + license);
|
System.out.println("过期日期: " + expiryDate);
|
System.out.println();
|
|
// 测试License验证
|
System.out.println("开始验证License...");
|
boolean isValid = initializeLicense(license);
|
System.out.println("License验证结果: " + isValid);
|
|
if (isValid) {
|
System.out.println("License信息:");
|
System.out.println(getLicenseInfo());
|
|
// 测试License有效性检查
|
System.out.println("\n当前License是否有效: " + isLicenseValid());
|
System.out.println("剩余天数: " + getRemainingDays());
|
} else {
|
System.err.println("License验证失败,系统无法启动");
|
}
|
|
} catch (Exception e) {
|
System.err.println("测试过程中发生错误: " + e.getMessage());
|
e.printStackTrace();
|
}
|
}
|
}
|