基于 TrueLicense 项目证书生成
一、创建公钥私钥
1、首先要用 KeyTool 工具来生成私匙库:(-alias别名 -validity 3650 表示10年有效,这个时间不是License的过期时间)
keytool -genkey -alias privatekey -keysize 1024 -keystore privateKeys.store -validity 3650
2、然后把私匙库内的证书导出到一个文件当中
keytool -export -alias privatekey -file certfile.cer -keystore privateKeys.store
3、然后再把这个证书文件导入到公匙库
keytool -import -alias publiccert -file certfile.cer -keystore publicCerts.store
根据提示的信息进行填写,完成后将生成三个文件,
- certfile.cer 不知道干嘛的,没去研究;
- privateKeys.store 用于当前的 ServerDemo 项目给客户生成license文件;
- publicCerts.store 则随应用代码部署到客户服务器,用户解密license文件并校验其许可信息;
二、生成证书文件
创建一个maven项目,将privateKeys.store放到创建的项目中去,
引入依赖文件
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.schlichtherle.truelicense</groupId>
<artifactId>truelicense-core</artifactId>
<version>1.33</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.35</version>
</dependency>
新建一个Java文件,
public static void main( String[] args ) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入访问密钥库的密码(使用 keytool 生成密钥对时设置的密码):");
String keyStorePwd = scanner.nextLine();
System.out.print("请输入生成密钥对的密码(需要妥善保管,不能让使用者知道):");
String privateKeyPwd = scanner.nextLine();
System.out.print("请输入项目的唯一识别码:");
String projectId = scanner.nextLine();
System.out.print("请输入发布日期(yyyy-MM-dd):");
String releaseDate = scanner.nextLine();
System.out.print("请输入有效开始日期(yyyy-MM-dd):");
String startDate = scanner.nextLine();
System.out.print("请输入截止日期(yyyy-MM-dd):");
String expirationDate = scanner.nextLine();
System.out.print("请输入要注册的MAC地址:");
String mac = scanner.nextLine();
System.out.print("请输入证书说明:");
String info = scanner.nextLine();
String property = System.getProperty("user.dir") + "\\license.lic";
Map<String, Object> map = new HashMap<>();
map.put("alias", "privatekey");
map.put("privateKeyPwd", privateKeyPwd);
map.put("keyStorePwd", keyStorePwd);
map.put("projectId", projectId);
map.put("issuedTime", releaseDate);
map.put("notBefore", startDate);
map.put("notAfter", expirationDate);
map.put("macAddress", mac);
map.put("info", info);
map.put("licPath", property);
try {
CreateLicense clicense = new CreateLicense(map);
clicense.create();
System.out.println("正在生成文件");
for (int i = 0; i <= 100; i++) {
printSchedule(i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println();
logger.info("证书生成成功!");
logger.info("证书路径:" + property);
}catch(IllegalPasswordException illegalPasswordException) {
logger.error("文件生成失败!密码与默认策略不匹配:至少6个字符,由字母和数字组成!");
illegalPasswordException.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private static int TOTLE_LENGTH = 20;
public static void printSchedule(int percent){
for (int i = 0; i < TOTLE_LENGTH + 10; i++) {
System.out.print("\b");
}
int now = TOTLE_LENGTH * percent / 100;
for (int i = 0; i < now; i++) {
System.out.print(">");
}
for (int i = 0; i < TOTLE_LENGTH - now; i++) {
System.out.print(" ");
}
System.out.print(" 已完成" + percent + "%");
}
创建两个工具类
import de.schlichtherle.license.*;
import javax.security.auth.x500.X500Principal;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.prefs.Preferences;
/**
* @version 1.0
* @description
**/
public class CreateLicense {
/**
* X500Princal 是一个证书文件的固有格式,详见API
*/
private final static X500Principal DEFAULT_HOLDERAND_ISSUER = new X500Principal("CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US");
private String priAlias;
private String privateKeyPwd;
private String keyStorePwd;
private String subject;
private String priPath;
private String issued;
private String notBefore;
private String notAfter;
private String macAddress;
private String consumerType;
private int consumerAmount;
private String info;
private String licPath;
/**
* 构造器,参数初始化
*/
public CreateLicense(Map<String, Object> map) {
// 私钥的别名
priAlias = (String) map.get("alias");
privateKeyPwd = (String) map.get("privateKeyPwd");
keyStorePwd = (String) map.get("keyStorePwd");
subject = (String) map.get("projectId");
// 密钥库的地址(放在 resource 目录下)
priPath = "/privateKeys.store";
issued = (String) map.get("issuedTime");
notBefore = (String) map.get("notBefore");
notAfter = (String) map.get("notAfter");
macAddress = (String) map.get("macAddress");
consumerType = "user";
consumerAmount = 1;
info = (String) map.get("info");
licPath = (String) map.get("licPath");
}
/**
* 生成证书,在证书发布者端执行
* 18-31-BF-0F-28-D6
* @throws Exception
*/
public void create() throws Exception {
LicenseManager licenseManager = LicenseManagerHolder.getLicenseManager(initLicenseParams());
licenseManager.store(buildLicenseContent(), new File(licPath));
System.out.println("------ 证书发布成功 ------");
}
/**
* 初始化证书的相关参数
* @return
*/
private LicenseParam initLicenseParams() {
Class<CreateLicense> clazz = CreateLicense.class;
Preferences preferences = Preferences.userNodeForPackage(clazz);
// 设置对证书内容加密的对称密码
CipherParam cipherParam = new DefaultCipherParam(keyStorePwd);
// 参数 1,2 从哪个Class.getResource()获得密钥库;
// 参数 3 密钥库的别名;
// 参数 4 密钥库存储密码;
// 参数 5 密钥库密码
KeyStoreParam privateStoreParam = new DefaultKeyStoreParam(clazz, priPath, priAlias, keyStorePwd, privateKeyPwd);
// 返回生成证书时需要的参数
return new DefaultLicenseParam(subject, preferences, privateStoreParam, cipherParam);
}
/**
* 通过外部配置文件构建证书的的相关信息
*
* @return
* @throws ParseException
*/
public LicenseContent buildLicenseContent() throws ParseException {
LicenseContent content = new LicenseContent();
SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd");
content.setConsumerAmount(consumerAmount);
content.setConsumerType(consumerType);
content.setHolder(DEFAULT_HOLDERAND_ISSUER);
content.setIssuer(DEFAULT_HOLDERAND_ISSUER);
content.setIssued(formate.parse(issued));
content.setNotBefore(formate.parse(notBefore));
content.setNotAfter(formate.parse(notAfter));
content.setInfo(info);
// 扩展字段
Map<String, String> map = new HashMap<>(4);
map.put("mac", macAddress);
content.setExtra(map);
return content;
}
}
运行main方法,输入对应的信息即可生成文件;
四、证书的使用
将生成的license.lic和publicCerts.store文件放到项目中的resources文件夹中,并在resources中创建licenseVerifyParam.properties配置文件信息,
########## 公钥的配置信息 ###########
# 公钥别名
public.alias=test123
# 该密码是访问密钥库的密码 — 使用 keytool 生成密钥对时设置,使用者知道该密码
key.store.pwd=test123
# 项目的唯一识别码 — 和私钥的 subject 保持一致
subject = test
# 证书路径(放在 resource 目录下)
license.dir=/license.lic
# 公共库路径(放在 resource 目录下)
public.store.path=/publicCerts.store
创建文件检查license,分别在项目启动和定时任务中检查
import com.superscene.xopendisplayserver.common.config.License.VerifyLicense;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
/**
* @version 1.0
* @description 服务权限检查类
**/
@Slf4j
@Configuration
@EnableScheduling
public class AuthorityConfig implements CommandLineRunner {
private static volatile VerifyLicense vlicense = null;
/**
* @description 服务启动检查
**/
@Override
public void run(String... args) {
vlicense = new VerifyLicense();
vlicense.install();
if (!vlicense.vertify()) {
Runtime.getRuntime().halt(1);
} else {
log.info("证书安装成功");
}
}
/**
* @description 定时检查权限
**/
@Scheduled(cron = "0 1 0 1/1 * ?")
private void configureTasks() {
vlicense.install();
if (!vlicense.vertify()) {
Runtime.getRuntime().halt(1);
}
}
}
import com.superscene.xopendisplayserver.common.utils.ComputerTools;
import de.schlichtherle.license.*;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.prefs.Preferences;
import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX;
import static org.springframework.util.ResourceUtils.getFile;
/**
* @version 1.0
* @description
**/
@Slf4j
public class VerifyLicense {
private String pubAlias;
private String keyStorePwd;
private String subject;
private String licDir;
private String pubPath;
public VerifyLicense() {
// 读取默认配置
setConf("/licenseVerifyParam.properties");
}
public VerifyLicense(String confPath) {
setConf(confPath);
}
/**
* 通过外部配置文件获取配置信息
*
* @param confPath 配置文件路径
*/
private void setConf(String confPath) {
// 获取参数
Properties prop = new Properties();
InputStream in = getClass().getResourceAsStream(confPath);
try {
prop.load(in);
} catch (IOException e) {
log.error("VerifyLicense Properties load inputStream error.", e);
}
this.subject = prop.getProperty("subject");
this.pubAlias = prop.getProperty("public.alias");
this.keyStorePwd = prop.getProperty("key.store.pwd");
this.licDir = prop.getProperty("license.dir");
this.pubPath = prop.getProperty("public.store.path");
}
/**
* 安装证书证书
*/
public void install() {
try {
LicenseManager licenseManager = getLicenseManager();
File file = getFile(CLASSPATH_URL_PREFIX + licDir);
licenseManager.install(file);
LicenseContent verify = licenseManager.verify();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String issued = formatter.format(verify.getIssued());
String notAfter = formatter.format(verify.getNotAfter());
log.info("发布日期:" + issued);
log.info("到期日期:" + notAfter);
} catch (Exception e) {
log.error("安装证书失败!", e);
Runtime.getRuntime().halt(1);
}
}
private LicenseManager getLicenseManager() {
return LicenseManagerHolder.getLicenseManager(initLicenseParams());
}
/**
* 初始化证书的相关参数
*/
private LicenseParam initLicenseParams() {
Class<VerifyLicense> clazz = VerifyLicense.class;
Preferences pre = Preferences.userNodeForPackage(clazz);
CipherParam cipherParam = new DefaultCipherParam(keyStorePwd);
KeyStoreParam pubStoreParam = new DefaultKeyStoreParam(clazz, pubPath, pubAlias, keyStorePwd, null);
return new DefaultLicenseParam(subject, pre, pubStoreParam, cipherParam);
}
/**
* 验证证书的合法性 issued notBefore notAfter
*/
public boolean vertify() {
try {
LicenseManager licenseManager = getLicenseManager();
LicenseContent verify = licenseManager.verify();
Map<String, String> extra = (Map) verify.getExtra();
String mac = extra.get("mac");
String localMac = ComputerTools.getMacAddress();
if (!Objects.equals(mac, localMac)) {
log.error("MAC 地址验证不通过");
return false;
}
log.info("验证证书成功!");
return true;
} catch (LicenseContentException ex) {
log.error("证书已经过期!", ex);
return false;
} catch (Exception e) {
log.error("验证证书失败!", e);
return false;
}
}
public static void main(String[] args) {
VerifyLicense vlicense = new VerifyLicense();
vlicense.install();
if (!vlicense.vertify()) {
Runtime.getRuntime().halt(1);
} else {
System.out.println("安装成功");
}
}
}
import de.schlichtherle.license.LicenseManager;
import de.schlichtherle.license.LicenseParam;
/**
* @version 1.0
* @description
**/
public class LicenseManagerHolder {
private static volatile LicenseManager licenseManager = null;
private LicenseManagerHolder() {
}
public static LicenseManager getLicenseManager(LicenseParam param) {
if (licenseManager == null) {
synchronized (LicenseManagerHolder.class) {
if (licenseManager == null) {
licenseManager = new LicenseManager(param);
}
}
}
return licenseManager;
}
}
至此就结束了,虽然并没有实质性的卵用,但是老板要,我也没办法,所有的代码都在上面了,基本拉过去就可以直接使用,仅做分享,有不足的地方还希望各位大佬指点。
基于 TrueLicense 项目证书生成的更多相关文章
- 基于 TrueLicense 的项目证书验证
一.简述 开发的软件产品在交付使用的时候,往往有一段时间的试用期,这期间我们不希望自己的代码被客户二次拷贝,这个时候 license 就派上用场了,license 的功能包括设定有效期.绑定 ip.绑 ...
- openssl实现双向认证教程(服务端代码+客户端代码+证书生成)
一.背景说明 1.1 面临问题 最近一份产品检测报告建议使用基于pki的认证方式,由于产品已实现https,商量之下认为其意思是使用双向认证以处理中间人形式攻击. <信息安全工程>中接触过 ...
- 基于X.509证书和SSL协议的身份认证过程实现(OpenSSL可以自己产生证书,有TCP通过SSL进行实际安全通讯的实际编程代码)good
上周帮一个童鞋做一个数字认证的实验,要求是编程实现一个基于X.509证书认证的过程,唉!可怜我那点薄弱的计算机网络安全的知识啊!只得恶补一下了. 首先来看看什么是X.509.所谓X.509其实是一种非 ...
- 转:基于开源项目OpenCV的人脸识别Demo版整理(不仅可以识别人脸,还可以识别眼睛鼻子嘴等)【模式识别中的翘楚】
文章来自于:http://blog.renren.com/share/246648717/8171467499 基于开源项目OpenCV的人脸识别Demo版整理(不仅可以识别人脸,还可以识别眼睛鼻子嘴 ...
- C#开发 “因为某项目未能生成,所以无法发布”
今天把笔记本电脑中开发的项目复制到台式机上,启用调试都正常.准备发布的时候却提示“因为某项目未能生成,所以无法发布”的错误. 从网上查找资料可以通过以下方法解决: 在项目属性的签名标签中,创建测试证书 ...
- 基于数据库的自动化生成工具,自动生成JavaBean、自动生成数据库文档等(v4.1.2版)
目录: 第1版:http://blog.csdn.net/vipbooks/article/details/51912143 第2版:htt ...
- Grunt-Kmc基于KISSY项目打包
Grunt-Kmc基于KISSY项目打包 1. Grunt-Kmc 是基于nodejs开发的,所以未安装nodeJS,先需要安装nodejs.安装步骤如下: 1. 下载安装文件,下载地址 ...
- 基于TrueLicense实现产品License验证功能
受朋友所托,需要给产品加上License验证功能,进行试用期授权,在试用期过后,产品不再可用. 通过研究调查,可以利用Truelicense开源框架实现,下面分享一下如何利用Truelicense实现 ...
- jar包打包成exe示例(基于maven项目)
jar包打包成exe示例(基于maven项目) 说明 针对基于maven的Java项目,通常会打包成jar, 如果要把jar文件包装成exe文件,仅需要在pom.xml配置文件中增加一个插件即可 这里 ...
- 在 .Net 项目中生成Report小记
背景 项目为WinForm + WCF 的应用,按照给定格式生成Report,显示在WinForm窗体上并可以导出为PDF和Excel文件. 分析 之前用过DevExpress For WinForm ...
随机推荐
- vue带有参数的路由跳转 动态路由
先定义好路由在router文件下面创建一个新的文件夹里面写上自己定义的路由 export default { path: '/detail/:id', component: () => ...
- 剑指Offer-55.链表中环的入口结点(C++/Java)
题目: 给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null. 分析: 利用快慢指针,如果链表中存在环的话,则快指针一定在环中的某个节点与慢指针相遇. 设头节点到链表的环的入口结点 ...
- SpringBoot系列(二) 环境搭建,创建我的第一个程序HelloWord。
环境准备: jdk1.8:java version "1.8.0_231",详见链接 maven3.x:maven3.3以上版本,详见链接 IDEA2021:IntelliJ ID ...
- ubuntu server 22.04 安装docker
ubuntu server 22.04 安装docker 官方安装文档: https://docs.docker.com/engine/install/ubuntu/ 1.更新软件列表: sudo a ...
- java线程常见的几种方法
线程常见的几种方法 标签(空格分隔): 多线程 Thread静态方法 1. Thread.sleep(misseconeds) 睡眠:当前线程暂停一段时间让给别的线程去运行.Sleep复活时间,根据你 ...
- 字符串— trim()、trimStart() 和 trimEnd()
在今天的教程中,我们将一起来学习JavaScript 字符串trim().trimStart() 和 trimEnd(). 01.trim() 学习如何使用 JavaScript trim()方法从 ...
- WatchDog:一款.NET开源的实时应用监控系统
项目介绍 WatchDog是一个开源(MIT License).免费.针对ASP.Net Core Web应用程序和API的实时应用监控系统.开发者可以实时记录和查看他们的应用程序中的消息.事件.HT ...
- python logging日志没有写入到指定文件,写到其他项目的日志文件
背景: 项目A为主框架项目,使用到了项目B的方法 项目A.B均有封装好的日志方法,且均在封装好的日志文件里面,增加了logger = MyLogger().info,其他文件要使用日志时,引入logg ...
- Android自动化-如何获取视图元素属性?
在做Android自动化时候,我们需要知道视图有哪些元素,元素都有哪些属性,获取到属性我们才能获取到元素从而做自动化控制,所以做Android自动化获取元素属性是必要的第一步 获取视图元素属性最便捷的 ...
- 2023/3/21 组会:ChatGPT 对数据增强的影响及 ChatGPT 的鲁棒性,Dense 和 Document 检索方法
前两个也许跟上了,后两个完全没跟上,以后再详细读读吧qwq 反正组会跟不上才是正常现象. AugGPT: Leveraging ChatGPT for Text Data Augmentation 摘 ...