让盗版无处可逃!SpringBoot 实现智能许可证验证全攻略!
·
点击上方“程序员蜗牛g”,选择“设为星标”
跟蜗牛哥一起,每天进步一点点

程序员蜗牛g
大厂程序员一枚 跟蜗牛一起 每天进步一点点
33篇原创内容
公众号
本文将带你构建一个基于 Spring Boot + RSA2048 非对称加密的许可证控制系统,支持硬件绑定、功能权限校验与离线验证。
整体方案安全、轻量、易扩展,可无缝嵌入现有的 Spring Boot 系统中。
许可证机制的核心是非对称加密体系。 厂商使用私钥生成许可证签名,客户端使用公钥验证真伪。
系统架构如下:
/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;@Componentpublic 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;@Componentpublic 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 项目中轻松实现本地化许可证验证, 还可以构建出一套可扩展的商业授权闭环系统。
当你的软件开始被复制、破解时,这套系统将成为它最强的“守护盾”—— 让盗版无处可逃,让你的商业价值安全可控。
如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。
关注公众号:woniuxgg,在公众号中回复:笔记 就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!
更多推荐


所有评论(0)