讓盜版無處可逃!SpringBoot 實現智能許可證驗證全攻略!
在軟件產品走向商業化的過程中,許可證驗證系統(License System)就像一道智能防線,既是企業的利潤保障線,也是合規與風控的重要工具。 無論是企業級 ERP 系統、桌面工具,還是在線 SaaS 服務,都離不開對授權、時間、功能和設備的嚴格管理。
一個完善的許可證控制系統,通常具備以下四大價值:
- 保護知識產權:防止軟件被復制或盜用。
- 支撐商業模式:實現按功能或時間授權。
- 精準用戶管控:明確授權對象與使用范圍。
- 滿足合規要求:方便企業做軟件資產審計。
本文將帶你構建一個基于 Spring Boot + RSA2048 非對稱加密的許可證控制系統,支持硬件綁定、功能權限校驗與離線驗證。 整體方案安全、輕量、易擴展,可無縫嵌入現有的 Spring Boot 系統中。
系統設計思路
許可證機制的核心是非對稱加密體系。 廠商使用私鑰生成許可證簽名,客戶端使用公鑰驗證真偽。 這種設計的三大優勢是:
- 高安全性:私鑰只由廠商持有,公鑰公開無風險;
- 部署簡單:支持完全離線驗證,無需獨立 License 服務器;
- 擴展性強:可靈活加入多種驗證維度(硬件、功能、時間等)。
系統架構如下:
/com/icoderoad/license
├── controller # REST接口層
├── service # 核心業務邏輯(簽發、驗證)
├── util # 硬件信息 & RSA 工具類
└── model # License 數據模型技術選型
模塊 | 技術棧 | 功能說明 |
后端框架 | Spring Boot 3.x | 核心業務支撐 |
數據序列化 | Jackson | JSON 序列化與反序列化 |
安全組件 | Java Security API | 提供 RSA 簽名算法 |
加密算法 | RSA2048 / SHA256withRSA / Base64 | 數字簽名、驗證 |
前端 | Vue + Element + TailwindCSS | 授權管理后臺 |
通訊協議 | RESTful API | 標準化前后端交互 |
核心模塊實現
硬件指紋采集工具類(HardwareUtil)
硬件指紋是許可證防偽的關鍵一環。 下面的工具類可跨平臺獲取主板序列號,并自動適配 Windows / Linux 環境:
package com.icoderoad.license.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.*;
import java.nio.charset.StandardCharsets;
@Component
public class HardwareUtil {
private static final Logger logger = LoggerFactory.getLogger(HardwareUtil.class);
/** 獲取主板序列號,支持 Windows 與 Linux */
public String getMotherboardSerial() {
String os = System.getProperty("os.name").toLowerCase();
try {
if (os.contains("windows")) return getWindowsSerial();
else if (os.contains("linux")) return getLinuxSerial();
else {
logger.warn("不支持的操作系統: {}", os);
return "UNKNOWN";
}
} catch (Exception e) {
logger.error("獲取主板序列號失敗", e);
return "UNKNOWN";
}
}
private String getWindowsSerial() throws Exception {
Process process = Runtime.getRuntime().exec("wmic baseboard get serialnumber");
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
if (!line.trim().isEmpty() && !line.contains("SerialNumber")) {
return line.trim();
}
}
}
process.waitFor();
return "UNKNOWN";
}
private String getLinuxSerial() throws Exception {
try {
Process process = Runtime.getRuntime().exec("sudo dmidecode -s baseboard-serial-number");
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
String line = reader.readLine();
if (line != null && !line.trim().isEmpty() && !line.contains("Not Specified"))
return line.trim();
}
} catch (Exception e) {
logger.warn("dmidecode 執行失敗,嘗試讀取 sys 文件", e);
}
return readFromSys();
}
private String readFromSys() {
try {
Process process = Runtime.getRuntime().exec("cat /sys/class/dmi/id/board_serial");
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
String line = reader.readLine();
if (line != null && !line.isEmpty()) return line.trim();
}
} catch (Exception e) {
logger.warn("讀取 /sys 文件失敗", e);
}
return "UNKNOWN";
}
}設計亮點:
- 支持多操作系統兼容;
- 異常兜底機制,保證系統穩定;
- 日志精細記錄,方便排查;
- 全程 UTF-8 編碼,避免亂碼。
RSA 工具類(RSAUtil)
提供密鑰生成、數字簽名與驗簽的完整工具集:
package com.icoderoad.license.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.security.*;
import java.security.spec.*;
import java.util.Base64;
@Component
public class RSAUtil {
private static final Logger logger = LoggerFactory.getLogger(RSAUtil.class);
private static final String ALGO = "RSA";
private static final String SIGN_ALGO = "SHA256withRSA";
/** 生成密鑰對 */
public KeyPair generateKeyPair() throws Exception {
KeyPairGenerator gen = KeyPairGenerator.getInstance(ALGO);
gen.initialize(2048);
KeyPair keyPair = gen.generateKeyPair();
logger.info("RSA 密鑰對生成成功");
return keyPair;
}
/** 簽名 */
public String sign(String data, PrivateKey privateKey) throws Exception {
Signature sig = Signature.getInstance(SIGN_ALGO);
sig.initSign(privateKey);
sig.update(data.getBytes());
return Base64.getEncoder().encodeToString(sig.sign());
}
/** 驗簽 */
public boolean verify(String data, String signBase64, PublicKey publicKey) throws Exception {
Signature sig = Signature.getInstance(SIGN_ALGO);
sig.initVerify(publicKey);
sig.update(data.getBytes());
return sig.verify(Base64.getDecoder().decode(signBase64));
}
}License 模型定義
package com.icoderoad.license.model;
import com.fasterxml.jackson.annotation.*;
import java.time.LocalDate;
import java.util.List;
@JsonPropertyOrder({"subject","issuedTo","hardwareId","expireAt","features"})
public class License {
private String subject;
private String issuedTo;
private String hardwareId;
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate expireAt;
private List<String> features;
private String signature;
// getter / setter / toString 省略
}核心業務服務:LicenseService
該類負責許可證的簽發與驗證全流程。
package com.icoderoad.license.model;
import com.fasterxml.jackson.annotation.*;
import java.time.LocalDate;
import java.util.List;
@JsonPropertyOrder({"subject","issuedTo","hardwareId","expireAt","features"})
public class License {
private String subject;
private String issuedTo;
private String hardwareId;
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate expireAt;
private List<String> features;
private String signature;
// getter / setter / toString 省略
}REST 接口層
package com.icoderoad.license.controller;
import com.icoderoad.license.model.License;
import com.icoderoad.license.service.LicenseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.security.*;
import java.util.*;
@RestController
@RequestMapping("/api/license")
public class LicenseController {
@Autowired private LicenseService licenseService;
private KeyPair cachedKeyPair;
@PostMapping("/generate-keys")
public Map<String, Object> generateKeys() throws Exception {
cachedKeyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
Map<String, Object> res = new HashMap<>();
res.put("publicKey", Base64.getEncoder().encodeToString(cachedKeyPair.getPublic().getEncoded()));
res.put("privateKey", Base64.getEncoder().encodeToString(cachedKeyPair.getPrivate().getEncoded()));
return res;
}
@PostMapping("/generate")
public String generateLicense(@RequestBody License license) throws Exception {
return licenseService.generateLicense(license, cachedKeyPair.getPrivate());
}
@PostMapping("/verify")
public String verifyLicense(@RequestBody String licenseJson) throws Exception {
boolean result = licenseService.verifyLicense(licenseJson, cachedKeyPair.getPublic());
return result ? "驗證通過" : "驗證失敗";
}
}系統安全機制總結
校驗維度 | 說明 |
數字簽名驗證 | 保證許可證未被篡改 |
硬件指紋綁定 | 限定授權設備 |
到期時間檢測 | 防止過期使用 |
JSON 標準化 | 確保簽名內容一致性 |
結語:從“授權管理”到“商業壁壘”
通過本方案,你不僅能在 Spring Boot 項目中輕松實現本地化許可證驗證, 還可以構建出一套可擴展的商業授權閉環系統。
未來可繼續擴展:
- 支持云端授權同步(License Server)
- 增加功能級授權粒度(模塊化 License)
- 結合加密狗、序列號、用戶賬號體系實現多重防護
當你的軟件開始被復制、破解時,這套系統將成為它最強的“守護盾”—— 讓盜版無處可逃,讓你的商業價值安全可控。























