在开发的基础框架代码中使用了base-license文件夹,该模块主要实现的功能为对于lic文件的验证,其中不包含license文件的生成,本文主要讲解如何生成license文件。
license文件简单概况就是授权文件,在代码中,我们使用TrueLicense开源的证书管理来实现授权文件的生成、验证等;
在生成授权文件前,首先需要密钥对
插入:密钥对分为公钥与私钥,私钥需要本地储存不泄露,公钥需要对外提供;私钥内部包含证书,对于授权文件进行数字签名,相当于加密的步骤,公钥则是在验证步骤时使用。
生成密钥对的工具有很多,鉴于开发过程中团队使用的都是JAVA,使用了JDK自带的KeyTool作为生成工具。
在JDK中
打开CMD,在系统环境变量已配置java相关后,可以使用。语句示例
keytool -genkey -alias privatekey -keystore privateKeys.store -validity 3650
keytool -genkey -alias 密钥别称 -keystore 储存位置,上面默认储存在cmd当前路径下 -validity 密钥有效日期
之后会需要输入密钥的访问密码,务必留好记录
密码规则是英文数字与符号,6位以上。
输入并重复密码后,会输入相关信息,可以比较随意,目前没有发现问题。
keytool -export -alias privatekey -file certfile.cer -keystore privateKeys.store
keytool -export -alias 密钥别名 -file 导出的证书文件 -keystore 密钥位置
keytool -import -alias publiccert -file certfile.cer -keystore publicCerts.store
keytool -import -alias 公钥别称 -file 导入的证书文件 -keystore 公钥位置
以上三步全部完成后,会在本地生成3个文件
privateKeys.keystore:私钥,不能泄露。
publicCerts.keystore:公钥,配合license进行授权信息的校验。
certfile.cer:证书,已导入公钥,无用。
记录好公钥别称,私钥别称,公钥私钥密码等所输入的信息
生成的工具类代码放在下面
首先是重写储存路径的类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
找不到文件,路径写错或者名称写错,使用带中文的路径也会出现此问题
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信