基于TrueLicense实现产品License验证功能

发布时间:2019-03-09

概述

基于TrueLicense实现产品License验证功能,给产品加上License验证功能,进行试用期授权,在试用期过后,产品不再可用。

详细

TrueLicense是一个开源的证书管理引擎,使用场景:当项目交付给客户之后用签名来保证客户不能随意使用项目 默认校验了开始结束时间,可扩展增加mac地址校验等。 其中还有ftp的校验没有尝试,本demo详细介绍的是本地校验 license授权机制的原理: 生成密钥对,方法有很多。我们使用trueLicense来做软件产品的保护,我们主要使用它的LicenseManager类来生成证书文件、安装证书文件、验证证书文件.


一、首先我们来看下效果图

image.png

image.png

二、下面的流程图为简略的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,即版权许可证,一般用于收费软件给付费用户提供的访问许可证明。根据应用部署位置的不同,一般可以分为以下两种情况讨论:

  • 应用部署在开发者自己的云服务器上。这种情况下用户通过账号登录的形式远程访问,因此只需要在账号登录的时候校验目标账号的有效期、访问权限等信息即可。

  • 应用部署在客户的内网环境。因为这种情况开发者无法控制客户的网络环境,也不能保证应用所在服务器可以访问外网,因此通常的做法是使用服务器许可文件,在应用启动的时候加载证书,然后在登录或者其他关键操作的地方校验证书的有效性。

六、项目结构图

image.png

本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码