1.使用license項目證書管理

1.license

代碼地址

通過license控制項目證書驗證

我才用的TrueLicense實現(xiàn)lic

首先介紹下 license 授權機制的原理:
    生成密鑰對檩互,包含私鑰和公鑰钝吮。
    授權者保留私鑰吵取,使用私鑰對授權信息諸如使用截止日期膨蛮,mac 地址等內容生成 license 簽名證書到推。
    公鑰給使用者掖看,放在代碼中使用演训,用于驗證 license 簽名證書是否符合使用條件

2.生成公私鑰

1.生成私鑰
keytool -genkey -alias privatekey -keystore privateKeys.store -keysize 1024 -validity 3650
//-validity 3650 表示有效期為10年
// 我這邊設值密碼為123456a, 密令執(zhí)行成功會產生文件privateKeys.store

2.生成certfile.cer(證書)
keytool -export -alias privatekey -file certfile.cer -keystore privateKeys.store

3.生成 publicCerts.store
keytool -import -alias publiccert -file certfile.cer -keystore publicCerts.store

lic1.png

3.生成licence.lic

api "de.schlichtherle.truelicense:truelicense-core:1.33"

licenseCreator

/**
 * License生成類 -- 用于license生成
 */
public class LicenseCreator {

    private final static X500Principal DEFAULT_HOLDER_AND_ISSUER = new X500Principal("CN=a, OU=a, O=a, L=a, ST=a, C=a");

    private static Logger logger = LogManager.getLogger(LicenseCreator.class);

    private License license;

    public LicenseCreator(License license) {
        this.license = license;
    }

    /**
     * 生成License證書
     */
    public boolean generateLicense() {
        try {
            LicenseManager licenseManager = new CustomLicenseManager(initLicenseParam());
            LicenseContent licenseContent = initLicenseContent();
            licenseManager.store(licenseContent, new File(license.getLicensePath()));
            return true;
        } catch (Exception e) {
            logger.error(MessageFormat.format("證書生成失斝聘怼:{0}", license), e);
            return false;
        }
    }

    /**
     * 初始化證書生成參數(shù)
     */
    private LicenseParam initLicenseParam() {
        Preferences preferences = Preferences.userNodeForPackage(LicenseCreator.class);

        //設置對證書內容加密的秘鑰
        CipherParam cipherParam = new DefaultCipherParam(license.getStorePass());

        KeyStoreParam privateStoreParam = new CustomKeyStoreParam(LicenseCreator.class
                , license.getPrivateKeysStorePath()
                , license.getPrivateAlias()
                , license.getStorePass()
                , license.getKeyPass());

        return new DefaultLicenseParam(license.getSubject()
                , preferences
                , privateStoreParam
                , cipherParam);
    }

    /**
     * 設置證書生成正文信息
     */
    private LicenseContent initLicenseContent() {
        LicenseContent licenseContent = new LicenseContent();
        licenseContent.setHolder(DEFAULT_HOLDER_AND_ISSUER);
        licenseContent.setIssuer(DEFAULT_HOLDER_AND_ISSUER);

        licenseContent.setSubject(license.getSubject());
        licenseContent.setIssued(license.getIssuedTime());
        licenseContent.setNotBefore(license.getIssuedTime());
        licenseContent.setNotAfter(license.getExpiryTime());
        licenseContent.setConsumerType(license.getConsumerType());
        licenseContent.setConsumerAmount(license.getConsumerAmount());
        licenseContent.setInfo(license.getDescription());

        //擴展校驗,這里可以自定義一些額外的校驗信息(也可以用json字符串保存)
        if (license.getLicenseExtraModel() != null) {
            licenseContent.setExtra(license.getLicenseExtraModel());
        }

        return licenseContent;
    }

}

License信息

@Data
public class License implements Serializable {

    private static final long serialVersionUID = -7793154252684580872L;

    /**
     * 證書subject
     */
    private String subject;

    /**
     * 私鑰別稱
     */
    private String privateAlias;

    /**
     * 私鑰密碼(需要妥善保管虑啤,不能讓使用者知道)
     */
    private String keyPass;

    /**
     * 訪問私鑰庫的密碼
     */
    private String storePass;

    /**
     * 證書生成路徑
     */
    private String licensePath;

    /**
     * 私鑰庫存儲路徑
     */
    private String privateKeysStorePath;

    /**
     * 證書生效時間
     */
    private Date issuedTime = new Date();

    /**
     * 證書失效時間
     */
    private Date expiryTime;

    /**
     * 用戶類型
     */
    private String consumerType = "user";

    /**
     * 用戶數(shù)量
     */
    private Integer consumerAmount = 1;

    /**
     * 描述信息
     */
    private String description = "";

    /**
     * 額外的服務器硬件校驗信息
     */
    private LicenseExtraModel licenseExtraModel;
}

LicenseExtraModel其它自定義的參數(shù)

/**
 * 自定義需要校驗的License參數(shù)隙弛,可以增加一些額外需要校驗的參數(shù),比如項目信息狞山,ip地址信息等等全闷,待完善
 */
@Data
public class LicenseExtraModel {

    // 這里可以添加一些往外的自定義信息,比如我們可以增加項目驗證萍启,客戶電腦sn碼的驗證等等
    private Boolean flag;

}

生成license

public static void main(String[] args) {
        // 生成license需要的一些參數(shù)
        License param = new License();
        // 證書授權主體
        param.setSubject("summit");
        // 私鑰別名
        param.setPrivateAlias("privateKey");
        // 私鑰密碼(需要妥善保管总珠,不能讓使用者知道)
        param.setKeyPass("123456a");
        // 訪問私鑰庫的密碼
        param.setStorePass("123456a");
        // 證書存儲地址
        param.setLicensePath("C:\\java-kaifa\\tongyu-workspace\\me\\springboot-jar\\my-stater\\src\\main\\resources\\license.lic");
        // 私鑰庫所在地址
        param.setPrivateKeysStorePath("C:\\java-kaifa\\tongyu-workspace\\me\\springboot-jar\\my-stater\\privateKeys.store");
        // 證書生效時間
        Calendar issueCalendar = Calendar.getInstance();
        param.setIssuedTime(issueCalendar.getTime());
        // 證書失效時間
        Calendar expiryCalendar = Calendar.getInstance();
        // 設置當前時間
        expiryCalendar.setTime(new Date());
        // 往后延長一年 = 授權一年時間
        expiryCalendar.add(Calendar.YEAR, 1);
        param.setExpiryTime(expiryCalendar.getTime());
        // 用戶類型
        param.setConsumerType("user");
        // 用戶數(shù)量
        param.setConsumerAmount(1);
        // 描述
        param.setDescription("測試");

        LicenseExtraModel model = new LicenseExtraModel();
        model.setFlag(true);
        param.setLicenseExtraModel(model);
        LicenseCreator licenseCreator = new LicenseCreator(param);
        // 生成license
        licenseCreator.generateLicense();
    }

4.驗證license

public class LicenseVerify {

    private static Logger logger = LogManager.getLogger(LicenseVerify.class);

    /**
     * 證書subject
     */
    private String subject;

    /**
     * 公鑰別稱
     */
    private String publicAlias;

    /**
     * 訪問公鑰庫的密碼
     */
    private String storePass;

    /**
     * 證書生成路徑
     */
    private String licensePath;

    /**
     * 密鑰庫存儲路徑
     */
    private String publicKeysStorePath;

    /**
     * LicenseManager
     */
    private LicenseManager licenseManager;

    /**
     * 額外參數(shù)
     */
    private LicenseExtraModel licenseExtraParam;

    public LicenseExtraModel getLicenseExtraParam() {
        return licenseExtraParam;
    }

    /**
     * 標識證書是否安裝成功
     */
    private boolean installSuccess;

    public LicenseVerify(String subject, String publicAlias, String storePass, String licensePath, String publicKeysStorePath) {
        this.subject = subject;
        this.publicAlias = publicAlias;
        this.storePass = storePass;
        this.licensePath = licensePath;
        this.publicKeysStorePath = publicKeysStorePath;
    }

    /**
     * 安裝License證書,讀取證書相關的信息, 在bean加入容器的時候自動調用
     */
    public void installLicense() {
        try {
            Preferences preferences = Preferences.userNodeForPackage(LicenseVerify.class);

            CipherParam cipherParam = new DefaultCipherParam(storePass);

            KeyStoreParam publicStoreParam = new CustomKeyStoreParam(LicenseVerify.class,
                    publicKeysStorePath,
                    publicAlias,
                    storePass,
                    null);
            LicenseParam licenseParam = new DefaultLicenseParam(subject, preferences, publicStoreParam, cipherParam);

            licenseManager = new CustomLicenseManager(licenseParam);
            licenseManager.uninstall();
            LicenseContent licenseContent = licenseManager.install(new File(licensePath));
            licenseExtraParam = (LicenseExtraModel) licenseContent.getExtra();

            DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            installSuccess = true;
            logger.info("------------------------------- 證書安裝成功 -------------------------------");
            logger.info(MessageFormat.format("證書有效期:{0} - {1}", format.format(licenseContent.getNotBefore()), format.format(licenseContent.getNotAfter())));
        } catch (Exception e) {
            installSuccess = false;
            logger.error("------------------------------- 證書安裝失敗 -------------------------------");
            logger.error(e);
        }
    }

    /**
     * 卸載證書勘纯,在bean從容器移除的時候自動調用
     */
    public void unInstallLicense() {
        if (installSuccess) {
            try {
                licenseManager.uninstall();
            } catch (Exception e) {
                // ignore
            }
        }
    }

    /**
     * 校驗License證書
     */
    public boolean verify() {
        try {
            LicenseContent licenseContent = licenseManager.verify();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

}

測試

public static void main(String[] args) {
        LicenseVerify licenseVerify = new LicenseVerify("summit", "publiccert", "123456b",
                "C:\\java-kaifa\\tongyu-workspace\\me\\springboot-jar\\my-stater\\src\\main\\resources\\license.lic",
                "C:\\java-kaifa\\tongyu-workspace\\me\\springboot-jar\\my-stater\\src\\main\\resources\\publicCerts.store"
        );

        licenseVerify.installLicense();
        licenseVerify.verify();
    }

// 打印結果
//> Task :my-stater:VerifyMain.main()
//16:21:08.553 [main] INFO cn.summit.licence.comm.LicenseVerify - ------------------------------- 證書安裝成功 -----------------
//16:21:08.559 [main] INFO cn.summit.licence.comm.LicenseVerify - 證書有效期:2022-07-28 16:20:28 - 2023-07-28 16:20:28

5.集合project

代碼見代碼地址

@Configuration
public class LicenseConfig {

    @Bean(initMethod = "installLicense", destroyMethod = "unInstallLicense")
    public LicenseVerify licenseVerify() {
        return new LicenseVerify(subject, publicAlias, storePass, licensePath, publicKeysStorePath);
    }

    /**
     * 證書subject
     */
    @Value("${license.subject:summit}")
    private String subject;

    /**
     * 公鑰別稱
     */
    @Value("${license.publicAlias:publiccert}")
    private String publicAlias;

    /**
     * 訪問公鑰庫的密碼
     */
    @Value("${license.storePass:123456b}")
    private String storePass;

    /**
     * 證書生成路徑
     */
    @Value("${license.licensePath:C:\\java-kaifa\\tongyu-workspace\\me\\springboot-jar\\my-stater\\src\\main\\resources\\license.lic}")
    private String licensePath;

    /**
     * 密鑰庫存儲路徑
     */
    @Value("${license.publicKeysStorePath:classpath:publicCerts.store}")
    private String publicKeysStorePath;


}

實際使用中可以將項目中一些參數(shù)放入LicenseExtraModel對象局服,在項目啟動的時候控制一些業(yè)務上權限

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市驳遵,隨后出現(xiàn)的幾起案子淫奔,更是在濱河造成了極大的恐慌,老刑警劉巖堤结,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唆迁,死亡現(xiàn)場離奇詭異鸭丛,居然都是意外死亡,警方通過查閱死者的電腦和手機唐责,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門鳞溉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人妒蔚,你說我怎么就攤上這事穿挨。” “怎么了肴盏?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵科盛,是天一觀的道長。 經常有香客問我菜皂,道長贞绵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任恍飘,我火速辦了婚禮榨崩,結果婚禮上,老公的妹妹穿的比我還像新娘章母。我一直安慰自己母蛛,他們只是感情好,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布乳怎。 她就那樣靜靜地躺著彩郊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蚪缀。 梳的紋絲不亂的頭發(fā)上秫逝,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機與錄音询枚,去河邊找鬼违帆。 笑死,一個胖子當著我的面吹牛金蜀,可吹牛的內容都是我干的刷后。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼渊抄,長吁一口氣:“原來是場噩夢啊……” “哼惠险!你這毒婦竟也來了?” 一聲冷哼從身側響起抒线,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎渣慕,沒想到半個月后嘶炭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抱慌,經...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年眨猎,在試婚紗的時候發(fā)現(xiàn)自己被綠了抑进。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡睡陪,死狀恐怖寺渗,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情兰迫,我是刑警寧澤信殊,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站汁果,受9級特大地震影響涡拘,放射性物質發(fā)生泄漏。R本人自食惡果不足惜据德,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一鳄乏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧棘利,春花似錦橱野、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蝌焚,卻和暖如春裹唆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背只洒。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工许帐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人毕谴。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓成畦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親涝开。 傳聞我的和親對象是個殘疾皇子循帐,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內容