# license-generate
**Repository Path**: litingbin/license-generate
## Basic Information
- **Project Name**: license-generate
- **Description**: 使用TrueLicense 生成和验证License(服务器许可)
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 15
- **Forks**: 11
- **Created**: 2022-05-12
- **Last Updated**: 2025-06-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## license-generate
#### 介绍
使用TrueLicense 生成和验证License(服务器许可),及Springboot项目如何集成TrueLicense
### 二、原理
首先需要生成密钥对,方法有很多,JDK中提供的KeyTool即可生成。
授权者保留私钥,使用私钥对包含授权信息(如截止日期,MAC地址等)的license进行数字签名。
公钥交给使用者(放在验证的代码中使用),用于验证license是否符合使用条件。
### 三、使用Keytool命令生成密钥对
> Keytool 是一个Java 数据证书的管理工具 ,Keytool 将密钥(key)和证书(certificates)存在一个称为keystore的文件中 在keystore里,包含两种数据: 密钥实体(Key entity)——密钥(secret key)又或者是私钥和配对公钥(采用非对称加密) 可信任的证书实体(trusted certificate entries)——只包含公钥
### 四、生成密钥的流程
#### 1、首先要用KeyTool工具来生成私匙库:(-alias别名 –validity 3650表示10年有效)
> keytool -genkey -alias privatekey -keystore privateKeys.store -validity 3650 -keysize 1024
注意!!!默认的密码策略是6未数字与字母,如果不遵守会报错,我这里使用123456q;要使用1024长度的密钥,否则在使用truelicense的时候会报错

#### 2、然后把私匙库内的证书导出到一个文件当中
> keytool -export -alias privatekey -file certfile.cer -keystore privateKeys.store
会得到一个certfile.cer,此证书是为了给使用方创建公钥证书,再生产公钥后此证书就没有用了。

#### 3、然后再把这个证书文件导入到公匙库
> keytool -import -alias publiccert -file certfile.cer -keystore publicCerts.store
公钥的密码设置为了lee2205,获取到公钥库,publicCerts.store

> privateKeys.keystore:私钥,这个我们自己留着,不能泄露给别人。
> publicCerts.keystore:公钥,这个给客户用的。在我们程序里面就是用他配合license进行授权信息的校验的。
> certfile.cer:这个文件没啥用,可以删掉。
### 五、生成许可文件
首先修改 LicenseCreator 中的 DEFAULT_HOLDER_AND_ISSUER,
当然如果你使用我提供的私钥就不用修改,如果不是请根据你自己生成的秘钥,生成参数,传入。
CreatorTest 测试包中的类
修改许可证书保存的路径;私钥库所在地址;
修改holderAndIssuer,根据你自己生成私钥库的时候填写的内容。
可以修改授权时间 Calendar.MONTH-月|Calendar.DAY-日|Calendar.YEAR-年
> // 证书存储地址
> param.setLicensePath("E:\\license.lic");
> // 私钥库所在地址
> param.setPrivateKeysStorePath("F:\\source\\gitee\\license-creator\\src\\main\\resources\\privateKeys.store");
> X500Principal holderAndIssuer = new X500Principal("CN=Lee, OU=Lee, O=Lee, L=Dalian, ST=Liaoning, C=zn");
> // 授权3个月时间
> expiryCalendar.add(Calendar.MONTH, 3);
执行 GenTest.generateLicense() 方法,能够生成许可文件。

可以看到在E盘中已经生成了许可文件

### 六、将生成的许可文件及公钥配置给需要使用的文件项目中
此处使用springboot项目进行集成,首先需要将此工程打包。
首先需要将此工程打包后,传入maven私库或者导入项目,我这里上传到私库。

需要注意的事项: 发现是在通过keytool生成密钥对的时候,公、私钥库的密码不一样(与私钥密码无关),设置为一样的以后,就可以了。
#### 1、导入相关依赖
将上传到私库的包,导入到新建立的项目中,同时导入truelicense相关的依赖如下
```xml
org.lee
license-generate
1.0.0
de.schlichtherle.truelicense
truelicense-core
```
#### 2、在yaml文件中添加配置,文件路径及公钥库密码请根据你自己的实际情况配置
```yaml
license:
subject: test-license
public-alias: publicCert
public-store-pass: 123456q
license-path: E:\license\license.lic
public-keys-store-path: E:\license\publicCerts.store
```
#### 3、 创建校验类及拦截器
首先创建校验类,然后创建拦截器;通过拦截器校验器去调用校验方法,如果许可超过有效期则进行提示。
```java
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import de.schlichtherle.license.*;
import lombok.extern.slf4j.Slf4j;
import org.lee.license.manager.CustomLicenseManager;
import org.lee.license.param.CustomKeyStoreParam;
import java.io.File;
import java.util.prefs.Preferences;
/**
* License校验类
*/
@Slf4j
public class LicenseVerify {
/**
* 证书subject
*/
private final String subject;
/**
* 公钥别称
*/
private final String publicAlias;
/**
* 访问公钥库的密码
*/
private final String storePass;
/**
* 证书生成路径
*/
private final String licensePath;
/**
* 密钥库存储路径
*/
private final String publicKeysStorePath;
/**
* LicenseManager
*/
private LicenseManager licenseManager;
/**
* 标识证书是否安装成功
*/
private boolean installSuccess;
public LicenseVerify(String subject, String publicAlias, String storePass, String licensePath, String publicKeysStorePath) {
this.subject = subject;
this.publicAlias = publicAlias;
this.storePass = storePass;
this.licensePath = licensePath;
this.publicKeysStorePath = publicKeysStorePath;
}
/**
* 安装License证书,读取证书相关的信息, 在bean加入容器的时候自动调用
*/
public void installLicense() {
try {
Preferences preferences = Preferences.userNodeForPackage(LicenseVerify.class);
CipherParam cipherParam = new DefaultCipherParam(storePass);
KeyStoreParam publicStoreParam = new CustomKeyStoreParam(LicenseVerify.class,
publicKeysStorePath,
publicAlias,
storePass,
null);
LicenseParam licenseParam = new DefaultLicenseParam(subject, preferences, publicStoreParam, cipherParam);
licenseManager = new CustomLicenseManager(licenseParam);
licenseManager.uninstall();
LicenseContent licenseContent = licenseManager.install(new File(licensePath));
installSuccess = true;
log.error("------------------------------- 证书安装成功 -------------------------------");
log.error("证书有效期:{} - {}", DateUtil.format(licenseContent.getNotBefore(), DatePattern.NORM_DATETIME_PATTERN), DateUtil.format(licenseContent.getNotAfter(), DatePattern.NORM_DATETIME_PATTERN));
} catch (Exception e) {
installSuccess = false;
e.printStackTrace();
log.error("------------------------------- 证书安装成功 -------------------------------");
log.error("证书已经超期");
}
}
/**
* 卸载证书,在bean从容器移除的时候自动调用
*/
public void unInstallLicense() {
if (installSuccess) {
try {
licenseManager.uninstall();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
/**
* 校验License证书
*/
public boolean verify() {
try {
licenseManager.verify();
return true;
} catch (Exception e) {
return false;
}
}
}
```
```java
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* @author ltb
* @date 2022/5/11
*/
@Component
public class ValidateTimeInterceptor implements HandlerInterceptor {
@Resource
private LicenseVerify licenseVerify;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
if (!licenseVerify.verify()) {
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
JSONObject retData = new JSONObject();
retData.put("code", 500);
retData.put("msg", "您的证书无效,请核查服务器是否取得授权或重新申请证书!");
response.getWriter().write(retData.toJSONString());
return false;
}
return true;
}
}
```
#### 4、创建配置类,配置方法能够安装上许可证书
```java
import com.hstech.license.LicenseVerify;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class LicenseConfig {
/**
* 证书subject
*/
@Value("${license.subject}")
private String subject;
/**
* 公钥别称
*/
@Value("${license.public-alias}")
private String publicAlias;
/**
* 访问公钥库的密码
*/
@Value("${license.public-store-pass}")
private String storePass;
/**
* 证书生成路径
*/
@Value("${license.license-path}")
private String licensePath;
/**
* 密钥库存储路径
*/
@Value("${license.public-keys-store-path}")
private String publicKeysStorePath;
@Bean(initMethod = "installLicense", destroyMethod = "unInstallLicense")
public LicenseVerify licenseVerify() {
return new LicenseVerify(subject, publicAlias, storePass, licensePath, publicKeysStorePath);
}
}
```
#### 5、启动项目
可以在控制台上看到,有效期的起始时间

至此,对于使用truelicense的许可证书的使用就介绍完成了,都看到这里了,麻烦给个小星星,您的每个小星星都是对我的支持。