在开发的基础框架代码中使用了base-license文件夹,该模块主要实现的功能为对于lic文件的验证,其中不包含license文件的生成,本文主要讲解如何生成license文件。
license文件简单概况就是授权文件,在代码中,我们使用TrueLicense开源的证书管理来实现授权文件的生成、验证等;
1、生成前准备
在生成授权文件前,首先需要密钥对
插入:密钥对分为公钥与私钥,私钥需要本地储存不泄露,公钥需要对外提供;私钥内部包含证书,对于授权文件进行数字签名,相当于加密的步骤,公钥则是在验证步骤时使用。
生成密钥对的工具有很多,鉴于开发过程中团队使用的都是JAVA,使用了JDK自带的KeyTool作为生成工具。
在JDK中
1)创建私钥
打开CMD,在系统环境变量已配置java相关后,可以使用。语句示例
keytool -genkey -alias privatekey -keystore privateKeys.store -validity 3650
keytool -genkey -alias 密钥别称 -keystore 储存位置,上面默认储存在cmd当前路径下 -validity 密钥有效日期
之后会需要输入密钥的访问密码,务必留好记录
密码规则是英文数字与符号,6位以上。
输入并重复密码后,会输入相关信息,可以比较随意,目前没有发现问题。
2)导出证书
keytool -export -alias privatekey -file certfile.cer -keystore privateKeys.store
keytool -export -alias 密钥别名 -file 导出的证书文件 -keystore 密钥位置
3)导入证书并生成公钥
keytool -import -alias publiccert -file certfile.cer -keystore publicCerts.store
keytool -import -alias 公钥别称 -file 导入的证书文件 -keystore 公钥位置
以上三步全部完成后,会在本地生成3个文件
privateKeys.keystore:私钥,不能泄露。
publicCerts.keystore:公钥,配合license进行授权信息的校验。
certfile.cer:证书,已导入公钥,无用。
记录好公钥别称,私钥别称,公钥私钥密码等所输入的信息
2、授权文件生成
生成的工具类代码放在下面
首先是重写储存路径的类CustomKeyStoreParam
package com.hlyz.base.license.entity;
import de.schlichtherle.license.AbstractKeyStoreParam;
import org.springframework.util.ResourceUtils;
import java.io.*;
/**
* @author fanghao10
*/
public class CustomKeyStoreParam extends AbstractKeyStoreParam {
protected CustomKeyStoreParam(Class aClass, String s) {
super(aClass, s);
}
/**
* 公钥/私钥在磁盘上的存储路径
*/
private String storePath;
private String alias;
private String storePwd;
private String keyPwd;
public CustomKeyStoreParam(Class clazz, String resource, String alias, String storePwd, String keyPwd) {
super(clazz, resource);
this.storePath = resource;
this.alias = alias;
this.storePwd = storePwd;
this.keyPwd = keyPwd;
}
@Override
public String getAlias() {
return alias;
}
@Override
public String getStorePwd() {
return storePwd;
}
@Override
public String getKeyPwd() {
return keyPwd;
}
/**
* AbstractKeyStoreParam里面的getStream()方法默认文件是存储的项目中。
* 用于将公私钥存储文件存放到其他磁盘位置而不是项目中
*/
@Override
public InputStream getStream() throws IOException {
// return new FileInputStream(new File(storePath));
File file = ResourceUtils.getFile(storePath);
if (file.exists()) {
return new FileInputStream(file);
} else {
throw new FileNotFoundException(storePath);
}
}
}
然后是证书的生成工具类
package com.hlyz.base.license.manager;
import com.hlyz.base.license.entity.CustomKeyStoreParam;
import com.hlyz.base.license.entity.License;
import de.schlichtherle.license.*;
import lombok.extern.slf4j.Slf4j;
import javax.security.auth.x500.X500Principal;
import java.io.File;
import java.text.MessageFormat;
import java.util.prefs.Preferences;
/**
* License生成类 -- 用于license生成
* @author fanghao10
*/
@Slf4j
public class LicenseCreator {
private final static X500Principal DEFAULT_HOLDER_AND_ISSUER = new X500Principal("CN=GENMER, OU=GENM, O=GENM, L=FUZHOU, ST=FUJIAN, C=CHINA");
private License license;
public LicenseCreator(License license) {
this.license = license;
}
/**
* 生成License证书
*/
public boolean generateLicense() {
try {
LicenseManager licenseManager = new CustomLicenseManager(initLicenseParam());
LicenseContent licenseContent = initLicenseContent();
licenseManager.store(licenseContent, new File(license.getLicensePath()));
return true;
} catch (Exception e) {
log.error(MessageFormat.format("证书生成失败:{0}", license), e);
return false;
}
}
/**
* 初始化证书生成参数
*/
private LicenseParam initLicenseParam() {
Preferences preferences = Preferences.userNodeForPackage(LicenseCreator.class);
//设置对证书内容加密的秘钥
CipherParam cipherParam = new DefaultCipherParam(license.getStorePass());
KeyStoreParam privateStoreParam = new CustomKeyStoreParam(LicenseCreator.class
, license.getPrivateKeysStorePath()
, license.getPrivateAlias()
, license.getStorePass()
, license.getKeyPass());
return new DefaultLicenseParam(license.getSubject()
, preferences
, privateStoreParam
, cipherParam);
}
/**
* 设置证书生成正文信息
*/
private LicenseContent initLicenseContent() {
LicenseContent licenseContent = new LicenseContent();
licenseContent.setHolder(DEFAULT_HOLDER_AND_ISSUER);
licenseContent.setIssuer(DEFAULT_HOLDER_AND_ISSUER);
licenseContent.setSubject(license.getSubject());
licenseContent.setIssued(license.getIssuedTime());
licenseContent.setNotBefore(license.getIssuedTime());
licenseContent.setNotAfter(license.getExpiryTime());
licenseContent.setConsumerType(license.getConsumerType());
licenseContent.setConsumerAmount(license.getConsumerAmount());
licenseContent.setInfo(license.getDescription());
// 扩展校验,这里可以自定义一些额外的校验信息(用json字符串保存)
// 使用类保存偶有未知错误出现,可能会是json转换失败等难以预见的错误
if (license.getLicenseExtraModel() != null) {
licenseContent.setExtra(license.getLicenseExtraModel());
}
return licenseContent;
}
}
生成的工具类代码就这些,需要生成时在代码中使用如下
// 创建证书实体类
License param = new License();
/* 需要往证书中填充的信息
例如
param.setSubject("licTestSub");
*/
LicenseCreator licenseCreator = new LicenseCreator(param);
// 生成license
licenseCreator.generateLicense();
此时授权文件的生成地址会在参数中的LicensePath位置生成一个.lic文件,这个文件就是我们说的License
相关问题
java.util.prefs.WindowsPreferences <init> WARNING: Could not open/create prefs root node Software\JavaSoft\Prefs at root 0x80000002. Windows RegCreateKeyEx(...) returned error code 5. Exception in thread "main" de.schlichtherle.
注册表中没有相关路径,win+R 输入 regedit,新建一个HKEY_LOCAL_MACHINE\Software\JavaSoft\Prefs
Exception in thread "main" de.schlichtherle.license.IllegalPasswordException: The password does not match the default policy: At least six characters consisting of letters and digits!
密码不合规范
certificate is not yet valid
日期不符合现实
Exception in thread "main" java.io.FileNotFoundException
找不到文件,路径写错或者名称写错,使用带中文的路径也会出现此问题