truelicense實現(xiàn)JAVA的license機制(包括license生成和驗證)

原文來自:http://blog.csdn.net/luckymelina/article/details/22870665
開發(fā)的軟件產品在交付使用的時候,往往會授權一段時間的試用期,這個時候license就派上用場了。不同于在代碼中直接加上時間約束,需要重新授權的時候使用license可以避免修改源碼,改動部署,授權方直接生成一個新的license發(fā)送給使用方替換掉原來的license文件即可。下面將講述使用truelicense來實現(xiàn)license的生成和使用。Truelicense是一個開源的證書管理引擎,詳細介紹見https://truelicense.java.net/
一、首先介紹下license授權機制的原理:
1、 生成密鑰對,方法有很多。
2、 授權者保留私鑰,使用私鑰對包含授權信息(如使用截止日期,MAC地址等)的license進行數(shù)字簽名。
3、 公鑰給使用者(放在驗證的代碼中使用),用于驗證license是否符合使用條件。
接下來是本例制作license的具體步驟:
二、第一步:使用keytool生成密鑰對
以下命令在dos命令行執(zhí)行,注意當前執(zhí)行目錄,最后生成的密鑰對即在該目錄下:
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拷貝出來備用。
三、第二步:生成證書(該部分代碼由授權者獨立保管執(zhí)行)

1、  首先LicenseManagerHolder.java類:
package cn.melina.license;  
import de.schlichtherle.license.LicenseManager;  
import de.schlichtherle.license.LicenseParam;  
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) {  
        // 獲取參數(shù)  
        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 {  
            /************** 證書發(fā)布者端執(zhí)行 ******************/  
            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;  
    }  
  
    // 返回生成證書時需要的參數(shù)  
    private static LicenseParam initLicenseParams0() {  
        Preferences preference = Preferences  
                .userNodeForPackage(CreateLicense.class);  
        // 設置對證書內容加密的對稱密碼  
        CipherParam cipherParam = new DefaultCipherParam(STOREPWD);  
        // 參數(shù)1,2從哪個Class.getResource()獲得密鑰庫;參數(shù)3密鑰庫的別名;參數(shù)4密鑰庫存儲密碼;參數(shù)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();  
        //獲取參數(shù)  
        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
根據(jù)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) {  
        // 獲取參數(shù)  
        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() {         
        /************** 證書使用者端執(zhí)行 ******************/  
  
        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;  
    }  
  
    // 返回驗證證書需要的參數(shù)  
    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();  
        //獲取參數(shù)  
        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  
根據(jù)該驗證的properties可以看出,使用者只擁有公鑰,沒有私鑰,并且也只知道訪問密鑰庫的密碼,而不能知道生成密鑰對的密碼。
五、說明:
注意實際操作中,公鑰、私鑰、證書等文件的存放路徑。
以上代碼需要用到truelicense的一些包,可以自行網(wǎng)上搜,也可以下載我的完整工程,里面附帶了所需的jar包。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 服務器https配置 配置https操作說明文檔 1、查看服務器環(huán)境配置(tomcat和apache合并使用) 2...
    南京楊小兵閱讀 9,253評論 0 9
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,568評論 19 139
  • 一、打包JavaWeb應用 在Java中,使用"jar"命令來對將JavaWeb應用打包成一個War包,jar命令...
    月亮風閱讀 268評論 0 1
  • 一. Keytool創(chuàng)建和導入命令 創(chuàng)建keystore和密鑰對 為存在的keystore生成證書請求文件CSR ...
    sngths閱讀 6,465評論 0 1
  • 寫在前面 今天使用高德地圖為應用添加Key的時候,發(fā)現(xiàn)有一項需要用到安全碼SHA1,而SHA1存在于Keystor...
    代碼咖啡閱讀 27,163評論 5 34

友情鏈接更多精彩內容