SpringBoot實(shí)現(xiàn)License生成和校驗(yàn)的過程詳解
1.License應(yīng)用場(chǎng)景
在我們向客戶銷售商業(yè)軟件的時(shí)候,常常需要對(duì)所發(fā)布的軟件實(shí)行一系列管控措施,諸如驗(yàn)證使用者身份、軟件是否到期,以及保存版權(quán)信息和開發(fā)商詳情等。考慮到諸多應(yīng)用場(chǎng)景可能處于離線環(huán)境,無法依賴網(wǎng)絡(luò)進(jìn)行實(shí)時(shí)認(rèn)證,所以還需要考慮單機(jī)認(rèn)證時(shí)的防破解問題??傊?,License許可證利用HTTPS網(wǎng)站的證書和簽名技術(shù),一方面證明當(dāng)前使用者是申請(qǐng)License的本人,另一方面要防止惡意破解,并偽造篡改License達(dá)到白嫖的目的。
為什么使用License授權(quán)?
License的作用是什么呢?收費(fèi)軟件的License其目的肯定是防止用戶白嫖啦,所以License還應(yīng)該具有以下一些功能:
- 授權(quán)使用: 明確用戶需要滿足的使用條件,如單用戶、多用戶、企業(yè)內(nèi)部使用、全球使用等,并且通常會(huì)限定可安裝和激活的設(shè)備數(shù)量。
- 期限控制: 規(guī)定軟件的使用期限,可能是永久授權(quán),也可能是訂閱式授權(quán),到期后用戶需要續(xù)費(fèi)才能繼續(xù)使用。
- 限制功能: 根據(jù)不同等級(jí)的License,軟件可以提供不同等級(jí)的功能,例如基礎(chǔ)版、專業(yè)版、企業(yè)版等,License可以解鎖相應(yīng)版本的功能。
- 版權(quán)保護(hù): 重申軟件的知識(shí)產(chǎn)權(quán)歸屬,禁止未經(jīng)授權(quán)的復(fù)制、分發(fā)、反編譯、篡改或逆向工程等侵犯版權(quán)的行為。
- 法律保障: License作為法律合同,確立了軟件提供商和用戶之間的法律關(guān)系,明確了雙方的權(quán)利和責(zé)任,如果發(fā)生違反協(xié)議的情況,軟件提供商有權(quán)采取法律手段追究責(zé)任。
- 技術(shù)支持和升級(jí)服務(wù):部分License中會(huì)規(guī)定用戶是否有權(quán)享有免費(fèi)的技術(shù)支持、軟件更新和維護(hù)服務(wù),以及這些服務(wù)的有效期限。
- 合規(guī)性要求: 對(duì)于特殊行業(yè)或特定地區(qū),License可能還涉及到滿足特定法規(guī)、標(biāo)準(zhǔn)或認(rèn)證的要求。
歸納起來,我們可以總結(jié)出License的作用是:
- 控制軟件使用者的使用權(quán)限
- 申明軟件所有者的版權(quán)
- 規(guī)定軟件的使用規(guī)范
2.證書準(zhǔn)備
例如:私鑰庫密碼為 priwd123456,公鑰庫密碼為 pubwd123456,生成步驟如下:
# 1. 生成私鑰庫 # validity:私鑰的有效期(天) # alias:私鑰別稱 # keystore:私鑰庫文件名稱(生成在當(dāng)前目錄) # storepass:私鑰庫密碼(獲取 keystore 信息所需的密碼,密鑰庫口令) # keypass:別名條目的密碼(密鑰口令) keytool -genkeypair -keysize 1024 -validity 3650 -alias "privateKey" -keystore "privateKeys.keystore" -storepass "pubwd123456" -keypass "priwd123456" -dname "CN=localhost, OU=localhost, O=localhost, L=SH, ST=SH, C=CN" # 2. 把私鑰庫內(nèi)的公鑰導(dǎo)出到一個(gè)文件當(dāng)中 # alias:私鑰別稱 # keystore:私鑰庫的名稱(在當(dāng)前目錄查找) # storepass:私鑰庫的密碼 # file:證書名稱 keytool -exportcert -alias "privateKey" -keystore "privateKeys.keystore" -storepass "pubwd123456" -file "certfile.cer" # 3.再把這個(gè)證書文件導(dǎo)入到公鑰庫,certfile.cer 沒用了可以刪掉了 # alias:公鑰名稱 # file:證書名稱 # keystore:公鑰文件名稱 # storepass:公鑰庫密碼 keytool -import -alias "publicCert" -file "certfile.cer" -keystore "publicCerts.keystore" -storepass "pubwd123456"
3.代碼工程
實(shí)驗(yàn)?zāi)繕?biāo)
實(shí)現(xiàn)license生成和校驗(yàn)
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springboot-demo</artifactId> <groupId>com.et</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>SoftwareLicense</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>de.schlichtherle.truelicense</groupId> <artifactId>truelicense-core</artifactId> <version>1.33</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> </project>
生成license
先獲取服務(wù)器信息,然后拿到相關(guān)信息在生成License.lic
/** * Project Name: true-license * File Name: LicenseCreatorController * Package Name: com.example.demo.controller * Date: 2020/10/10 13:36 * Author: 方瑞冬 */ package com.et.license.controller; import com.et.license.license.LicenseCheckModel; import com.et.license.license.LicenseCreatorParam; import com.et.license.service.LicenseCreatorService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.Map; /** * @author 方瑞冬 */ @RestController @RequestMapping("/license") public class LicenseCreatorController { @Autowired private LicenseCreatorService licenseCreatorService; /** * <p>項(xiàng)目名稱: true-license-demo </p> * <p>文件名稱: LicenseCreatorController.java </p> * <p>方法描述: 獲取服務(wù)器硬件信息 </p> * <p>創(chuàng)建時(shí)間: 2020/10/10 13:39 </p> * * @param osName 系統(tǒng)名稱 * @return com.example.demo.license.LicenseCheckModel * @author 方瑞冬 * @version 1.0 */ @GetMapping("/getServerInfos") public LicenseCheckModel getServerInfos(@RequestParam String osName) { return licenseCreatorService.getServerInfos(osName); } /** * <p>項(xiàng)目名稱: true-license-demo </p> * <p>文件名稱: LicenseCreatorController.java </p> * <p>方法描述: 生成證書 </p> * <p>創(chuàng)建時(shí)間: 2020/10/10 13:42 </p> * * @param param 證書創(chuàng)建參數(shù) * @return java.util.Map<java.lang.String, java.lang.Object> * @author 方瑞冬 * @version 1.0 */ @PostMapping("/generateLicense") public Map<String, Object> generateLicense(@RequestBody LicenseCreatorParam param) { return licenseCreatorService.generateLicense(param); } } /** * Project Name: true-license * File Name: LicenseCreatorService * Package Name: com.example.demo.service * Date: 2020/10/10 13:44 * Author: 方瑞冬 */ package com.et.license.service; import com.et.license.license.LicenseCheckModel; import com.et.license.license.LicenseCreatorParam; import java.util.Map; /** * @author 方瑞冬 */ public interface LicenseCreatorService { /** * <p>項(xiàng)目名稱: true-license-demo </p> * <p>文件名稱: LicenseCreatorService.java </p> * <p>方法描述: 獲取服務(wù)器硬件信息 </p> * <p>創(chuàng)建時(shí)間: 2020/10/10 13:45 </p> * * @param osName 系統(tǒng)名稱 * @return com.example.demo.license.LicenseCheckModel * @author 方瑞冬 * @version 1.0 */ LicenseCheckModel getServerInfos(String osName); /** * <p>項(xiàng)目名稱: true-license-demo </p> * <p>文件名稱: LicenseCreatorService.java </p> * <p>方法描述: 生成證書 </p> * <p>創(chuàng)建時(shí)間: 2020/10/10 13:45 </p> * * @param param 證書創(chuàng)建參數(shù) * @return java.util.Map<java.lang.String, java.lang.Object> * @author 方瑞冬 * @version 1.0 */ Map<String, Object> generateLicense(LicenseCreatorParam param); } /** * Project Name: true-license * File Name: LicenseCreatorServiceImpl * Package Name: com.example.demo.service.impl * Date: 2020/10/10 13:44 * Author: 方瑞冬 */ package com.et.license.service.impl; import com.et.license.license.*; import com.et.license.service.LicenseCreatorService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import java.util.HashMap; import java.util.Map; /** * @author 方瑞冬 */ @Service public class LicenseCreatorServiceImpl implements LicenseCreatorService { @Autowired private LicenseConfig licenseConfig; /** * <p>項(xiàng)目名稱: true-license-demo </p> * <p>文件名稱: LicenseCreatorServiceImpl.java </p> * <p>方法描述: 獲取服務(wù)器硬件信息 </p> * <p>創(chuàng)建時(shí)間: 2020/10/10 13:46 </p> * * @param osName 系統(tǒng)名稱 * @return com.example.demo.license.LicenseCheckModel * @author 方瑞冬 * @version 1.0 */ @Override public LicenseCheckModel getServerInfos(String osName) { //操作系統(tǒng)類型 if (StringUtils.isEmpty(osName)) { osName = System.getProperty("os.name"); } osName = osName.toLowerCase(); AbstractServerInfos abstractServerInfos = null; //根據(jù)不同操作系統(tǒng)類型選擇不同的數(shù)據(jù)獲取方法 if (osName.startsWith("windows")) { abstractServerInfos = new WindowsServerInfos(); } else if (osName.startsWith("linux")) { abstractServerInfos = new LinuxServerInfos(); } else {//其他服務(wù)器類型 abstractServerInfos = new LinuxServerInfos(); } return abstractServerInfos.getServerInfos(); } /** * <p>項(xiàng)目名稱: true-license-demo </p> * <p>文件名稱: LicenseCreatorServiceImpl.java </p> * <p>方法描述: 生成證書 </p> * <p>創(chuàng)建時(shí)間: 2020/10/10 13:46 </p> * * @param param 證書創(chuàng)建參數(shù) * @return java.util.Map<java.lang.String, java.lang.Object> * @author 方瑞冬 * @version 1.0 */ @Override public Map<String, Object> generateLicense(LicenseCreatorParam param) { Map<String, Object> resultMap = new HashMap<>(2); if (StringUtils.isEmpty(param.getLicensePath())) { param.setLicensePath(licenseConfig.getLicensePath()); } LicenseCreator licenseCreator = new LicenseCreator(param); boolean result = licenseCreator.generateLicense(); if (result) { resultMap.put("result", "ok"); resultMap.put("msg", param); } else { resultMap.put("result", "error"); resultMap.put("msg", "證書文件生成失?。?); } return resultMap; } }
安裝和卸載license
/** * Project Name: true-license * File Name: LicenseConfig * Package Name: com.example.demo.license * Date: 2020/10/10 14:03 * Author: 方瑞冬 */ package com.et.license.license; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author 方瑞冬 * 證書配置 */ @Data @Configuration @ConfigurationProperties("license") @Slf4j public class LicenseConfig { /** * 證書 subject */ private String subject; /** * 公鑰別稱 */ private String publicAlias; /** * 訪問公鑰庫的密碼 */ private String storePass; /** * 證書生成路徑 */ private String licensePath; /** * 密鑰庫存儲(chǔ)路徑 */ private String publicKeysStorePath; /** * <p>項(xiàng)目名稱: true-license-demo </p> * <p>文件名稱: LicenseConfig.java </p> * <p>方法描述: 把 LicenseVerify 類添加到 Spring 容器。在 LicenseVerify 從 Spring 容器添加或移除的時(shí)候調(diào)用證書安裝或卸載 </p> * <p>創(chuàng)建時(shí)間: 2020/10/10 16:07 </p> * * @return com.example.demo.licensegenerate.LicenseVerify * @author 方瑞冬 * @version 1.0 */ @Bean(initMethod = "installLicense", destroyMethod = "unInstallLicense") public LicenseVerify licenseVerify() { return new LicenseVerify(subject, publicAlias, storePass, licensePath, publicKeysStorePath); } }
校驗(yàn)證書
package com.et.license; import com.et.license.license.LicenseVerify; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest class TrueLicenseApplicationTests { @Autowired private LicenseVerify licenseVerify; @Test void contextLoads() { System.out.println("licese是否有效:" + licenseVerify.verify()); } }
以上只是一些關(guān)鍵代碼,所有代碼請(qǐng)參見下面代碼倉庫
代碼倉庫
4.測(cè)試
啟動(dòng)Spring Boot應(yīng)用
獲取服務(wù)器信息
生成License.lic
請(qǐng)求報(bào)文
{ "subject":"license_demo", "privateAlias":"privateKey", "keyPass":"priwd123456", "storePass":"pubwd123456", "licensePath":"/Users/liuhaihua/IdeaProjects/springboot-demo/SoftwareLicense/src/main/resources/license/license.lic", "privateKeysStorePath":"/Users/liuhaihua/IdeaProjects/springboot-demo/SoftwareLicense/src/main/resources/license/privateKeys.keystore", "issuedTime":"2020-10-10 00:00:01", "expiryTime":"2025-10-09 23:59:59", "consumerType":"User", "consumerAmount":1, "description":"license demo", "licenseCheckModel":{ "ipAddress": [ "192.168.0.100" ], "macAddress": [ "F0-18-98-50-71-5F" ], "cpuSerial": null, "mainBoardSerial": null } }
結(jié)果
安裝證書
024-09-02 21:01:54.991 WARN 39586 --- [ main] o.s.boot.StartupInfoLogger : InetAddress.getLocalHost().getHostName() took 5003 milliseconds to respond. Please verify your network configuration (macOS machines may need to add entries to /etc/hosts). 2024-09-02 21:01:59.999 INFO 39586 --- [ main] com.et.license.DemoApplication : Starting DemoApplication on bogon with PID 39586 (/Users/liuhaihua/IdeaProjects/springboot-demo/SoftwareLicense/target/classes started by liuhaihua in /Users/liuhaihua/IdeaProjects/springboot-demo) 2024-09-02 21:02:00.001 INFO 39586 --- [ main] com.et.license.DemoApplication : No active profile set, falling back to default profiles: default 2024-09-02 21:02:00.767 INFO 39586 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2024-09-02 21:02:00.774 INFO 39586 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2024-09-02 21:02:00.774 INFO 39586 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.31] 2024-09-02 21:02:00.831 INFO 39586 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2024-09-02 21:02:00.832 INFO 39586 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 793 ms 2024-09-02 21:02:01.128 INFO 39586 --- [ main] com.et.license.license.LicenseVerify : ------------------------------- 證書安裝成功 ------------------------------- 2024-09-02 21:02:01.128 INFO 39586 --- [ main] com.et.license.license.LicenseVerify : 證書校驗(yàn)通過,證書有效期:2020-10-10 00:00:01 - 2025-10-09 23:59:59 2024-09-02 21:02:01.210 INFO 39586 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2024-09-02 21:02:01.344 INFO 39586 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2024-09-02 21:02:01.347 INFO 39586 --- [ main] com.et.license.DemoApplication : Started DemoApplication in 16.649 seconds (JVM running for 22.127) 2024-09-02 21:09:41.535 INFO 39586 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2024-09-02 21:09:41.538 INFO 39586 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2024-09-02 21:09:41.588 INFO 39586 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 50 ms
校驗(yàn)證書
運(yùn)行測(cè)試用例
2024-09-02 21:17:17.212 INFO 39937 --- [ main] com.et.license.license.LicenseVerify : 證書有效期:2020-10-10 00:00:01 - 2025-10-09 23:59:59 licese是否有效:true
以上就是SpringBoot實(shí)現(xiàn)License生成和校驗(yàn)的過程詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot License生成和校驗(yàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
IDEA連接mysql報(bào)錯(cuò)的問題及解決方法
這篇文章主要介紹了IDEA連接mysql報(bào)錯(cuò)的問題及解決方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08Spring中@DependsOn注解的使用代碼實(shí)例
這篇文章主要介紹了Spring中@DependsOn注解的使用代碼實(shí)例,Spring中@DependsOn,主要是使用在類和方法上, 作用是當(dāng)前對(duì)象要依賴另外一些對(duì)象,被依賴的對(duì)象會(huì)先注冊(cè)到Spring的IOC容器中,需要的朋友可以參考下2024-01-01mybatisplus?復(fù)合主鍵(多主鍵)?CRUD示例詳解
這篇文章主要介紹了mybatisplus?復(fù)合主鍵(多主鍵)?CRUD實(shí)例詳解,本文通過實(shí)例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03IntelliJ Plugin 開發(fā)之添加第三方j(luò)ar的示例代碼
這篇文章主要介紹了IntelliJ Plugin 開發(fā)之添加第三方j(luò)ar的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09基于application和bootstrap的加載順序及區(qū)別說明
這篇文章主要介紹了application和bootstrap的加載順序及區(qū)別說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07基于@RequestParam注解之Spring MVC參數(shù)綁定的利器
這篇文章主要介紹了基于@RequestParam注解之Spring MVC參數(shù)綁定的利器,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03