liujie
2026-01-21 8d1d546ad729da0e809e17e8161376adcc662c96
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
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();
        }
    }
}