偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Spring Boot 開發(fā)者必看:輕松搞定許可證管控,讓項目變現(xiàn)無憂!

開發(fā) 項目管理
本文將帶你實現(xiàn)一個基于?Spring Boot 3.x + RSA2048 非對稱加密?的許可證管理方案,覆蓋?硬件綁定、權限控制、到期驗證?等核心能力。我們將從整體架構(gòu)、技術選型,到代碼實現(xiàn)逐步拆解,并提供完整的 API 設計,幫助開發(fā)者快速構(gòu)建商業(yè)化必備的管控體系。

在軟件產(chǎn)品逐漸走向商業(yè)化的過程中,許可證管控已經(jīng)成為必不可少的環(huán)節(jié)。無論你是在構(gòu)建企業(yè)級管理系統(tǒng)、獨立桌面應用,還是在線化的 SaaS 服務,都需要一種可靠機制來限制授權范圍、控制功能模塊、以及設置到期時間。

缺少許可證機制,意味著你的軟件隨時可能被非法拷貝或無授權使用,直接威脅到商業(yè)收益與知識產(chǎn)權。而一個設計完善的許可證系統(tǒng)不僅能保證軟件安全,還能提供差異化定價策略,靈活支撐 按時間、按功能的付費模式。

因此,本文將帶你實現(xiàn)一個基于 Spring Boot 3.x + RSA2048 非對稱加密 的許可證管理方案,覆蓋 硬件綁定、權限控制、到期驗證 等核心能力。我們將從整體架構(gòu)、技術選型,到代碼實現(xiàn)逐步拆解,并提供完整的 API 設計,幫助開發(fā)者快速構(gòu)建商業(yè)化必備的管控體系。

系統(tǒng)設計思路

許可證系統(tǒng)基于 非對稱加密,核心邏輯如下:

  • 廠商端:使用私鑰對許可證文件進行簽名;
  • 客戶端:使用公鑰驗證許可證真實性;

這樣做的優(yōu)勢:

  1. 安全性高:私鑰僅存儲在廠商側(cè),公鑰即使被泄露也無法偽造許可證;
  2. 部署靈活:支持 離線校驗,不依賴中央服務器;
  3. 擴展性強:可以靈活加上 功能點控制、用戶數(shù)限制 等規(guī)則。

技術選型

  • 后端棧

Spring Boot 3.x → 快速開發(fā) Web API

Java Security API → 內(nèi)置 RSA 非對稱加密支持

Jackson → JSON 序列化和反序列化

  • 前端棧

原生 JavaScript → 保持輕量級

TailwindCSS → 快速構(gòu)建現(xiàn)代化 UI

RESTful API → 前后端標準交互

  • 加密算法

RSA2048 → 足夠安全的密鑰長度

SHA256withRSA → 數(shù)字簽名算法

Base64 → 簽名編碼

核心功能實現(xiàn)

以下代碼全部放在 Linux 風格的目錄結(jié)構(gòu)中,例如:

src/main/java/com/icoderoad/license

硬件指紋獲取

硬件綁定是防止盜版的第一道防線。我們以主板序列號作為唯一標識:

package com.icoderoad.license.util;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


import java.io.BufferedReader;
import java.io.InputStreamReader;
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("不支持的系統(tǒng): {}", 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) {
                line = line.trim();
                if (!line.isEmpty() && !"SerialNumber".equalsIgnoreCase(line)) {
                    return line;
                }
            }
        }
        process.waitFor();
        return "UNKNOWN";
    }


    private String getLinuxSerial() throws Exception {
        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.contains("Not Specified")) {
                return line.trim();
            }
        }
        process.waitFor();
        return getLinuxSerialFromSys();
    }


    private String getLinuxSerialFromSys() {
        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();
                return (line != null && !line.isEmpty()) ? line.trim() : "UNKNOWN";
            }
        } catch (Exception e) {
            logger.warn("讀取/sys失敗", e);
            return "UNKNOWN";
        }
    }
}

關鍵點:

  • 多重策略:優(yōu)先 dmidecode,失敗則 fallback 到 /sys/class/dmi/id
  • 異常兜底:保證失敗返回 "UNKNOWN"
  • 統(tǒng)一編碼:避免中文亂碼

RSA 加密工具類

用于密鑰生成、簽名、驗簽:

package com.icoderoad.license.crypto;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


import java.nio.charset.StandardCharsets;
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 ALGORITHM = "RSA";
    private static final String SIGN_ALGO = "SHA256withRSA";


    public KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
        keyGen.initialize(2048);
        logger.info("RSA密鑰對生成完成");
        return keyGen.generateKeyPair();
    }


    public String sign(String data, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance(SIGN_ALGO);
        signature.initSign(privateKey);
        signature.update(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(signature.sign());
    }


    public boolean verify(String data, String sign, PublicKey publicKey) throws Exception {
        Signature signature = Signature.getInstance(SIGN_ALGO);
        signature.initVerify(publicKey);
        signature.update(data.getBytes(StandardCharsets.UTF_8));
        return signature.verify(Base64.getDecoder().decode(sign));
    }


    public PrivateKey loadPrivateKey(String pem) throws Exception {
        String key = pem.replaceAll("-----\\w+ PRIVATE KEY-----", "").replaceAll("\\s", "");
        byte[] decoded = Base64.getDecoder().decode(key);
        return KeyFactory.getInstance(ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(decoded));
    }


    public PublicKey loadPublicKey(String pem) throws Exception {
        String key = pem.replaceAll("-----\\w+ PUBLIC KEY-----", "").replaceAll("\\s", "");
        byte[] decoded = Base64.getDecoder().decode(key);
        return KeyFactory.getInstance(ALGORITHM).generatePublic(new X509EncodedKeySpec(decoded));
    }
}

許可證實體類

package com.icoderoad.license.model;


import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;


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;


    // getters, setters, toString...
}

許可證服務邏輯

負責 生成許可證 和 驗證許可證

package com.icoderoad.license.service;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.icoderoad.license.crypto.RSAUtil;
import com.icoderoad.license.model.License;
import com.icoderoad.license.util.HardwareUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;


import java.security.PrivateKey;
import java.security.PublicKey;
import java.time.LocalDate;


@Service
public class LicenseService {


    private static final Logger logger = LoggerFactory.getLogger(LicenseService.class);


    private final RSAUtil rsaUtil;
    private final HardwareUtil hardwareUtil;
    private final ObjectMapper objectMapper;


    public LicenseService(RSAUtil rsaUtil, HardwareUtil hardwareUtil, ObjectMapper objectMapper) {
        this.rsaUtil = rsaUtil;
        this.hardwareUtil = hardwareUtil;
        this.objectMapper = objectMapper;
    }


    public String generateLicense(License license, PrivateKey privateKey) throws Exception {
        if (license.getHardwareId() == null) {
            license.setHardwareId(hardwareUtil.getMotherboardSerial());
        }
        String data = objectMapper.writeValueAsString(license);
        String signature = rsaUtil.sign(data, privateKey);


        ObjectNode node = (ObjectNode) objectMapper.readTree(data);
        node.put("signature", signature);


        return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(node);
    }


    public boolean verifyLicense(String licenseJson, PublicKey publicKey) {
        try {
            ObjectNode node = (ObjectNode) objectMapper.readTree(licenseJson);
            String signature = node.remove("signature").asText();
            License license = objectMapper.treeToValue(node, License.class);


            if (!rsaUtil.verify(objectMapper.writeValueAsString(license), signature, publicKey)) {
                return false;
            }
            if (!hardwareUtil.getMotherboardSerial().equals(license.getHardwareId())) {
                return false;
            }
            return !license.getExpireAt().isBefore(LocalDate.now());
        } catch (Exception e) {
            logger.error("驗證失敗", e);
            return false;
        }
    }
}

REST API

package com.icoderoad.license.controller;


import com.icoderoad.license.service.LicenseService;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/api/license")
@CrossOrigin
public class LicenseController {


    private final LicenseService licenseService;


    public LicenseController(LicenseService licenseService) {
        this.licenseService = licenseService;
    }


    @PostMapping("/generate")
    public String generateLicense() {
        // 簡化演示,實際需接收請求參數(shù)
        return "生成的許可證JSON...";
    }


    @PostMapping("/verify")
    public String verifyLicense(@RequestBody String licenseJson) {
        return licenseService.verifyLicense(licenseJson, null) ? "驗證通過" : "驗證失敗";
    }
}

總結(jié)

通過本文的實現(xiàn),我們構(gòu)建了一個 輕量級、可擴展、安全可靠 的許可證管控系統(tǒng),核心特性包括:

  • 非對稱加密保障安全 → 私鑰只存廠商,客戶端僅驗證公鑰
  • 硬件指紋綁定 → 防止許可證被隨意拷貝
  • 三重驗證機制 → 簽名 + 硬件 + 時間
  • 離線驗證能力 → 無需中心化服務器

這種設計既能保護軟件知識產(chǎn)權,又能靈活支持商業(yè)化運營(試用、訂閱、按功能收費)。 對于正計劃將軟件推向市場的開發(fā)者而言,這套方案是構(gòu)建 商業(yè)化閉環(huán) 的堅實基礎。

責任編輯:武曉燕 來源: 路條編程
相關推薦

2013-09-04 09:21:04

2017-11-01 15:20:55

開源開源許可證

2023-03-19 15:51:25

開源開源許可證開發(fā)

2013-07-17 10:16:57

Github項目許可證

2025-02-14 08:30:49

SpringJava開發(fā)

2014-07-09 10:53:58

軟件許可證

2024-12-12 08:44:14

JabbaJDK工具

2024-08-09 08:52:26

2016-07-22 15:34:35

WindowsWin10開發(fā)者

2021-03-29 12:54:31

Ruby許可證代碼

2009-07-23 09:25:28

SaaS成本

2011-05-05 09:41:56

開源軟件許可證

2012-11-12 09:34:03

SDNOpenStackCloudStack

2014-10-23 17:36:19

百度

2011-08-01 16:39:21

Xcode 目錄結(jié)構(gòu)

2011-08-04 10:32:33

Ruby 1.9.3BSD 許可證

2014-04-04 10:07:46

ApacheWinJS

2012-06-11 15:23:27

2018-08-24 09:32:15

開源技術 項目

2014-12-19 10:04:12

華為
點贊
收藏

51CTO技術棧公眾號