基于TrueLicense实现产品License验证功能
概述
详细
TrueLicense是一个开源的证书管理引擎,使用场景:当项目交付给客户之后用签名来保证客户不能随意使用项目 默认校验了开始结束时间,可扩展增加mac地址校验等。 其中还有ftp的校验没有尝试,本demo详细介绍的是本地校验 license授权机制的原理: 生成密钥对,方法有很多。我们使用trueLicense来做软件产品的保护,我们主要使用它的LicenseManager类来生成证书文件、安装证书文件、验证证书文件.
一、首先我们来看下效果图:
二、下面的流程图为简略的trueLicense验证证书文件的流程
三、介绍License授权和验证的原理
1、 首先需要生成密钥对,方法有很多,JDK中提供的KeyTool即可生成。
2、 授权者保留私钥,使用私钥对包含授权信息(如截止日期,MAC地址等)的license进行数字签名。
3、 公钥交给使用者(放在验证的代码中使用),用于验证license是否符合使用条件。
四、实现步骤
使用KeyTool生成密钥对
转到CMD命令行,切换到%JAVA_HOME%\jre\bin\security\ 目录(KeyTool工具一般在此目录),执行命令生成的密钥对:
1、首先利用KeyTool工具来生成私匙库:(-alias别名 –validity 3650表示10年有效)
keytool -genkey -alias privatekey -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
最后生成文件privateKeys.store、publicCerts.store拷贝出来备用。
生成证书(该部分代码由授权者独立保管执行)
1、 首先是 LicenseManagerHolder.java 类
public class LicenseManagerHolder { private static LicenseManager licenseManager; public static synchronized LicenseManager getLicenseManager(LicenseParam licenseParam) { if(null == licenseManager) { try { licenseManager = new LicenseManager(licenseParam); } catch (Exception e) { e.printStackTrace(); } } return licenseManager; } }
2、 然后是主要生成 license 的代码 CreateLicense.java
public class CreateLicense { //common param private static String PRIVATEALIAS = ""; private static String KEYPWD = ""; private static String STOREPWD = ""; private static String SUBJECT = ""; private static String licPath = ""; private static String priPath = ""; //license content private static String issuedTime = ""; private static String notBefore = ""; private static String notAfter = ""; private static String consumerType = ""; private static int consumerAmount = 0; private static String info = ""; // 为了方便直接用的API里的例子 // X500Princal是一个证书文件的固有格式,详见API private final static X500Principal DEFAULTHOLDERANDISSUER = new X500Principal( "CN=Duke、OU=JavaSoft、O=Sun Microsystems、C=US"); public void setParam(String propertiesPath) { // 获取参数 Properties prop = new Properties(); InputStream in = getClass().getResourceAsStream(propertiesPath); try { prop.load(in); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } PRIVATEALIAS = prop.getProperty("PRIVATEALIAS"); KEYPWD = prop.getProperty("KEYPWD"); STOREPWD = prop.getProperty("STOREPWD"); SUBJECT = prop.getProperty("SUBJECT"); KEYPWD = prop.getProperty("KEYPWD"); licPath = prop.getProperty("licPath"); priPath = prop.getProperty("priPath"); //license content issuedTime = prop.getProperty("issuedTime"); notBefore = prop.getProperty("notBefore"); notAfter = prop.getProperty("notAfter"); consumerType = prop.getProperty("consumerType"); consumerAmount = Integer.valueOf(prop.getProperty("consumerAmount")); info = prop.getProperty("info"); } public boolean create() { try { /************** 证书发布者端执行 ******************/ LicenseManager licenseManager = LicenseManagerHolder .getLicenseManager(initLicenseParams0()); licenseManager.store((createLicenseContent()), new File(licPath)); } catch (Exception e) { e.printStackTrace(); System.out.println("客户端证书生成失败!"); return false; } System.out.println("服务器端生成证书成功!"); return true; } // 返回生成证书时需要的参数 private static LicenseParam initLicenseParams0() { Preferences preference = Preferences .userNodeForPackage(CreateLicense.class); // 设置对证书内容加密的对称密码 CipherParam cipherParam = new DefaultCipherParam(STOREPWD); // 参数1,2从哪个Class.getResource()获得密钥库;参数3密钥库的别名;参数4密钥库存储密码;参数5密钥库密码 KeyStoreParam privateStoreParam = new DefaultKeyStoreParam( CreateLicense.class, priPath, PRIVATEALIAS, STOREPWD, KEYPWD); LicenseParam licenseParams = new DefaultLicenseParam(SUBJECT, preference, privateStoreParam, cipherParam); return licenseParams; } // 从外部表单拿到证书的内容 public final static LicenseContent createLicenseContent() { DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); LicenseContent content = null; content = new LicenseContent(); content.setSubject(SUBJECT); content.setHolder(DEFAULTHOLDERANDISSUER); content.setIssuer(DEFAULTHOLDERANDISSUER); try { content.setIssued(format.parse(issuedTime)); content.setNotBefore(format.parse(notBefore)); content.setNotAfter(format.parse(notAfter)); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } content.setConsumerType(consumerType); content.setConsumerAmount(consumerAmount); content.setInfo(info); // 扩展 content.setExtra(new Object()); return content; } }
3、 测试程序 licenseCreateTest.java
public class licenseCreateTest {
public static void main(String[] args){
CreateLicense cLicense = new CreateLicense();
//获取参数
cLicense.setParam("./createparam.properties");
//生成证书
cLicense.create();
}
}
、验证证书(使用证书)(该部分代码结合需要授权的程序一起使用)
1、 首先 LicenseManagerHolder.java 类,同上。
2、 然后是主要验证 license 的代码 VerifyLicense.java
public class VerifyLicense { //common param private static String PUBLICALIAS = ""; private static String STOREPWD = ""; private static String SUBJECT = ""; private static String licPath = ""; private static String pubPath = ""; public void setParam(String propertiesPath) { // 获取参数 Properties prop = new Properties(); InputStream in = getClass().getResourceAsStream(propertiesPath); try { prop.load(in); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } PUBLICALIAS = prop.getProperty("PUBLICALIAS"); STOREPWD = prop.getProperty("STOREPWD"); SUBJECT = prop.getProperty("SUBJECT"); licPath = prop.getProperty("licPath"); pubPath = prop.getProperty("pubPath"); } public boolean verify() { /************** 证书使用者端执行 ******************/ LicenseManager licenseManager = LicenseManagerHolder .getLicenseManager(initLicenseParams()); // 安装证书 try { licenseManager.install(new File(licPath)); System.out.println("客户端安装证书成功!"); } catch (Exception e) { e.printStackTrace(); System.out.println("客户端证书安装失败!"); return false; } // 验证证书 try { licenseManager.verify(); System.out.println("客户端验证证书成功!"); } catch (Exception e) { e.printStackTrace(); System.out.println("客户端证书验证失效!"); return false; } return true; } // 返回验证证书需要的参数 private static LicenseParam initLicenseParams() { Preferences preference = Preferences .userNodeForPackage(VerifyLicense.class); CipherParam cipherParam = new DefaultCipherParam(STOREPWD); KeyStoreParam privateStoreParam = new DefaultKeyStoreParam( VerifyLicense.class, pubPath, PUBLICALIAS, STOREPWD, null); LicenseParam licenseParams = new DefaultLicenseParam(SUBJECT, preference, privateStoreParam, cipherParam); return licenseParams; } }
3、 验证测试程序 licenseVerifyTest.java
public class licenseVerifyTest { public static void main(String[] args){ VerifyLicense vLicense = new VerifyLicense(); //获取参数 vLicense.setParam("./param.properties"); //验证证书 vLicense.verify(); } }
五、小结
License,即版权许可证,一般用于收费软件给付费用户提供的访问许可证明。根据应用部署位置的不同,一般可以分为以下两种情况讨论:
应用部署在开发者自己的云服务器上。这种情况下用户通过账号登录的形式远程访问,因此只需要在账号登录的时候校验目标账号的有效期、访问权限等信息即可。
应用部署在客户的内网环境。因为这种情况开发者无法控制客户的网络环境,也不能保证应用所在服务器可以访问外网,因此通常的做法是使用服务器许可文件,在应用启动的时候加载证书,然后在登录或者其他关键操作的地方校验证书的有效性。
六、项目结构图