• 热门专题

使用truelicense实现用于JAVA工程license机制(包括license生成和验证)

作者:  发布日期:2014-04-03 19:54:00
Tag标签:机制  工程  
  • 开发的软件产品在交付使用的时候,往往会授权一段时间的试用期,这个时候license就派上用场了。不同于在代码中直接加上时间约束,需要重新授权的时候使用license可以避免修改源码,改动部署,授权方直接生成一个新的license发送给使用方替换掉原来的license文件即可。下面将讲述使用truelicense来实现license的生成和使用。Truelicense是一个开源的证书管理引擎,详细介绍见https://truelicense.java.net/

    一、首先介绍下license授权机制的原理:

    1、 生成密钥对,方法有很多。

    2、 授权者保留私钥,使用私钥对包含授权信息(如使用截止日期,MAC地址等)的license进行数字签名。

    3、 公钥给使用者(放在验证的代码中使用),用于验证license是否符合使用条件。

     

    接下来是本例制作license的具体步骤:

    二、第一步:使用keytool生成密钥对

    以下命令在dos命令行执行,注意当前执行目录,最后生成的密钥对即在该目录下:

    1、首先要用KeyTool工具来生成私匙库:(-alias别名 –validity 3650表示10年有效)

    keytool -genkey -alias privatekey -keystoreprivateKeys.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类:

     

    package cn.melina.license;
    import de.schlichtherle.license.LicenseManager;
    import de.schlichtherle.license.LicenseParam;
    
    /**
     * LicenseManager??????
     * @author melina
     */
    public class LicenseManagerHolder {
    	
    	private static LicenseManager licenseManager;
     
    	public static synchronized LicenseManager getLicenseManager(LicenseParam licenseParams) {
        	if (licenseManager == null) {
        		licenseManager = new LicenseManager(licenseParams);
        	}
        	return licenseManager;
        }
    }
    

     

    2、 然后是主要生成license的代码CreateLicense.java:

    package cn.melina.license;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.text.DateFormat;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Properties;
    import java.util.prefs.Preferences;
    import javax.security.auth.x500.X500Principal;
    import de.schlichtherle.license.CipherParam;
    import de.schlichtherle.license.DefaultCipherParam;
    import de.schlichtherle.license.DefaultKeyStoreParam;
    import de.schlichtherle.license.DefaultLicenseParam;
    import de.schlichtherle.license.KeyStoreParam;
    import de.schlichtherle.license.LicenseContent;
    import de.schlichtherle.license.LicenseParam;
    import de.schlichtherle.license.LicenseManager;
    
    /**
     * CreateLicense
     * @author melina
     */
    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:

    package cn.melina.license;
    import cn.melina.license.CreateLicense;
    public class licenseCreateTest {
    	public static void main(String[] args){
    		CreateLicense cLicense = new CreateLicense();
    		//获取参数
    		cLicense.setParam("./param.properties");
    		//生成证书
    		cLicense.create();
    	}
    }
    

    4、 生成时使用到的param.properties文件如下:

    ##########common parameters###########
    #alias
    PRIVATEALIAS=privatekey
    #key(该密码生成密钥对的密码,需要妥善保管,不能让使用者知道)
    KEYPWD=bigdata123456
    #STOREPWD(该密码是在使用keytool生成密钥对时设置的密钥库的访问密码)
    STOREPWD=abc123456
    #SUBJECT
    SUBJECT=bigdata
    #licPath
    licPath=bigdata.lic
    #priPath
    priPath=privateKeys.store
    ##########license content###########
    #issuedTime
    issuedTime=2014-04-01
    #notBeforeTime
    notBefore=2014-04-01
    #notAfterTime
    notAfter=2014-05-01
    #consumerType
    consumerType=user
    #ConsumerAmount
    consumerAmount=1
    #info
    info=this is a license
    

    根据properties文件可以看出,这里只简单设置了使用时间的限制,当然可以自定义添加更多限制。该文件中表示授权者拥有私钥,并且知道生成密钥对的密码。并且设置license的内容。

    四、第三步:验证证书(使用证书)(该部分代码结合需要授权的程序使用)

     

    1、 首先LicenseManagerHolder.java类,同上。

    2、 然后是主要验证license的代码VerifyLicense.java:

    package cn.melina.license;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;
    import java.util.prefs.Preferences;
    
    import de.schlichtherle.license.CipherParam;
    import de.schlichtherle.license.DefaultCipherParam;
    import de.schlichtherle.license.DefaultKeyStoreParam;
    import de.schlichtherle.license.DefaultLicenseParam;
    import de.schlichtherle.license.KeyStoreParam;
    import de.schlichtherle.license.LicenseParam;
    import de.schlichtherle.license.LicenseManager;
    
    /**
     * VerifyLicense
     * @author melina
     */
    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:

    package cn.melina.license;
    
    public class licenseVerifyTest {
    	public static void main(String[] args){
    		VerifyLicense vLicense = new VerifyLicense();
    		//获取参数
    		vLicense.setParam("./param.properties");
    		//验证证书
    		vLicense.verify();
    	}
    }
    

    4、 验证时使用到的Properties文件如下:

    ##########common parameters###########
    #alias
    PUBLICALIAS=publiccert
    #STOREPWD(该密码是在使用keytool生成密钥对时设置的密钥库的访问密码)
    STOREPWD=abc123456
    #SUBJECT
    SUBJECT=bigdata
    #licPath
    licPath=bigdata.lic
    #pubPath
    pubPath=publicCerts.store
    

    根据该验证的properties可以看出,使用者只拥有公钥,没有私钥,并且也只知道访问密钥库的密码,而不能知道生成密钥对的密码。

    五、说明:

    注意实际操作中,公钥、私钥、证书等文件的存放路径。

    以上代码需要用到truelicense的一些包,可以自行网上搜,也可以下载我的完整工程,里面附带了所需的jar包。

     

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规