点击上方“程序员蜗牛g”,选择“设为星标”

跟蜗牛哥一起,每天进步一点点

程序员蜗牛g

大厂程序员一枚 跟蜗牛一起 每天进步一点点

33篇原创内容

公众号

本文将带你构建一个基于 Spring Boot + RSA2048 非对称加密的许可证控制系统,支持硬件绑定、功能权限校验与离线验证

 整体方案安全、轻量、易扩展,可无缝嵌入现有的 Spring Boot 系统中。

许可证机制的核心是非对称加密体系。 厂商使用私钥生成许可证签名,客户端使用公钥验证真伪。 

系统架构如下:

/com/icoderoad/license├── controller       # REST接口层├── service          # 核心业务逻辑(签发、验证)├── util             # 硬件信息 & RSA 工具类└── model            # License 数据模型

技术选型

模块技术栈功能说明
后端框架Spring Boot 3.x核心业务支撑
数据序列化JacksonJSON 序列化与反序列化
安全组件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实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐