zoukankan      html  css  js  c++  java
  • 使用truelicense实现用于JAVA工程license机制(包括license生成和验证)

    开发的软件产品在交付使用的时候,往往会授权一段时间的试用期,这个时候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(important!)
    KEYPWD=bigdata123456
    #STOREPWD
    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
    STOREPWD=abc123456
    #SUBJECT
    SUBJECT=bigdata
    #licPath
    licPath=bigdata.lic
    #pubPath
    pubPath=publicCerts.store

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

    五、说明:

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

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

    以上两个完整工程提供下载:http://download.csdn.net/detail/luckymelina/7141131

    GOOD LUCK!小伙伴们加油!欢迎与我交流。

    转载自:https://blog.csdn.net/luckymelina/article/details/22870665

  • 相关阅读:
    记第一场省选
    POJ 2083 Fractal 分形
    CodeForces 605A Sorting Railway Cars 思维
    FZU 1896 神奇的魔法数 dp
    FZU 1893 内存管理 模拟
    FZU 1894 志愿者选拔 单调队列
    FZU 1920 Left Mouse Button 简单搜索
    FZU 2086 餐厅点餐
    poj 2299 Ultra-QuickSort 逆序对模版题
    COMP9313 week4a MapReduce
  • 原文地址:https://www.cnblogs.com/rsty/p/9126819.html
Copyright © 2011-2022 走看看