技术:apache-maven-3.3.9 +jdk1.8.0_102
运行环境:ideaIC-2020.1.3 + apache-maven-3.3.9+ jdk1.8.0_102
家精品内容,核心代码解析
多代码预警~觉着有帮助的别忘了给小普点赞!
作者:陈鸿姣 编辑:Carol
01 概述
TrueLicense是一个开源的证书管理引擎,使用trueLicense来做软件产品的保护,基于TrueLicense实现产品License验证功能,给产品加上License验证功能,进行试用期授权,在试用期过后,产品不再可用。
02 使用场景
小普看来,当项目交付给客户之后用签名来保证客户不能随意使用项目,TrueLicense默认校验了开始结束时间,可扩展增加mac地址校验等。
因此,小普详细介绍的是本地校验 license授权机制的原理以及主要使用TrueLicense的LicenseManager类来生成证书文件、安装证书文件、验证证书文件等。
03 license授权机制的原理
原理如下:
(1)生成密钥对,包含私钥和公钥。(2)授权者保留私钥,使用私钥对授权信息诸如使用截止日期,mac 地址等内容生成 license 签名证书。(3)公钥给使用者,放在代码中使用,用于验证 license 签名证书是否符合使用条件。
04 使用KeyTool生成密匙库
使用jdk自带的KeyTool工具生成密钥库,这里使用的jdk版本是jdk1.8.0_102。首先我们找到KeyTool所在的目录,截图如下:
可以看到Windowscmd窗口如下:
生成密码库的步骤如下:
(1)生成密钥库
keytool -genkeypair-keysize 1024 -validity 3650-alias
"privateKey" -keystore "privateKeys.keystore"
(2)生成证书文件
keytool -exportcert -alias "privateKey" -keystore "privateKeys.keystore" -
file "certfile.cer"
(3)生成公钥库
keytool -import -alias "publicCert" -file "certfile.cer" -keystore
"publicCerts.keystore"
最后在D:\work soft\java\jdk1.8.0_102\jre\bin目录下:看到以下三个文件:
privateKeys.keystore(私钥)提供给生成证书使用
publicCerts. keystore(公钥)提供给证书认证使用
certfile.cer后续步骤用不到,可以删除。
05 Springboot+TrueLicense证书生成和认证
(1)引入jar包:
首先,我们需要引入 truelicense 的 jar 包,用于实现我们的证书管理。
(2)证书生成步骤以及核心实现代码
① 校验自定义的License参数。首先,创建自定义的可被允许的服务器硬件信息的实体类(如果校验其他参数,可自行补充).备注:如果只需要检验文件的生效和过期时间无需创建此类。
/**
* @author chenhongjiao
*/
@Data
public class LicenseCheckModelimplements Serializable {
private static final long serialVersionUID = 8600137500316662317L;
/**
* 可被允许的IP地址
*/
private List<String> ipAddress;
/**
* 可被允许的MAC地址
*/
private List<String> macAddress;
/**
* 可被允许的CPU序列号
*/
private String cpuSerial;
/**
* 可被允许的主板序列号
*/
private String mainBoardSerial;
}
② 其次,创建License生成需要的参数实体类
/**
* @author chenhongjiao
*/
@Data
public class LicenseCreatorParam implements Serializable {
private static final long serialVersionUID = -7793154252684580872L;
/**
* 证书subject
*/
private String subject;
/**
* 密钥别称
*/
private String privateAlias;
/**
* 密钥密码(需要妥善保管,不能让使用者知道)
*/
private String keyPass;
/**
* 访问秘钥库的密码
*/
private String storePass;
/**
* 证书生成路径
*/
private String licensePath;
/**
* 密钥库存储路径
*/
private String privateKeysStorePath;
/**
* 证书生效时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date issuedTime = new Date();
/**
* 证书失效时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date expiryTime;
/**
* 用户类型
*/
private String consumerType = "user";
/**
* 用户数量
*/
private Integer consumerAmount = 1;
/**
* 描述信息
*/
private String description = "";
/**
* 额外的服务器硬件校验信息,无需额外校验可去掉
*/
private LicenseCheckModel licenseCheckModel;
}
③添加抽象类AbstractServerInfos,用户获取服务器的硬件信息。
(备注:根据需要选择,无需额外校验可去掉)
@Slf4j
public abstract class AbstractServerInfos {
/**
* 组装需要额外校验的License参数
* @author chenhongjiao
* @date 2021/03/26 14:23
* @since 1.0.0
* @return LicenseCheckModel
*/
public LicenseCheckModel getServerInfos(){
LicenseCheckModel result = new LicenseCheckModel();
try {
result.setIpAddress(this.getIpAddress());
result.setMacAddress(this.getMacAddress());
result.setCpuSerial(this.getCPUSerial());
result.setMainBoardSerial(this.getMainBoardSerial());
}catch (Exception e){
log.error("获取服务器硬件信息失败",e);
}
return result;
}
/**
* 获取IP地址
* @author chenhongjiao
* @date 2021/03/26 11:32
* @since 1.0.0
* @return java.util.List<java.lang.String>
*/
protected abstract List<String> getIpAddress() throws Exception;
/**
* 获取Mac地址
* @author chenhongjiao
* @date 2021/03/26 11:32
* @since 1.0.0
* @return java.util.List<java.lang.String>
*/
protected abstract List<String> getMacAddress() throws Exception;
/**
* 获取CPU序列号
* @author chenhongjiao
* @date 2021/03/26 11:35
* @since 1.0.0
* @return java.lang.String
*/
protected abstract String getCPUSerial() throws Exception;
/**
* 获取主板序列号
* @author chenhongjiao
* @date 2021/03/26 11:35
* @since 1.0.0
* @return java.lang.String
*/
protected abstract String getMainBoardSerial() throws Exception;
/**
* 获取当前服务器所有符合条件的InetAddress
* @author chenhongjiao
* @date 2021/03/26 17:38
* @since 1.0.0
* @return java.util.List<java.net.InetAddress>
*/
protected List<InetAddress> getLocalAllInetAddress() throws Exception {
List<InetAddress> result = new ArrayList<>(4);
// 遍历所有的网络接口
for (Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); networkInterfaces.hasMoreElements(); ) {
NetworkInterface iface = (NetworkInterface) networkInterfaces.nextElement();
// 在所有的接口下再遍历IP
for (Enumeration inetAddresses = iface.getInetAddresses(); inetAddresses.hasMoreElements(); ) {
InetAddress inetAddr = (InetAddress) inetAddresses.nextElement();
//排除LoopbackAddress、SiteLocalAddress、LinkLocalAddress、MulticastAddress类型的IP地址
if(!inetAddr.isLoopbackAddress()
&& !inetAddr.isLinkLocalAddress() && !inetAddr.isMulticastAddress()){
result.add(inetAddr);
}
}
}
return result;
}
/**
* 获取某个网络接口的Mac地址
* @author chenhongjiao
* @date 2021/03/26 18:08
* @since 1.0.0
* @param
* @return void
*/
protected String getMacByInetAddress(InetAddress inetAddr){