Spring Boot项目中使用 TrueLicense 生成和验证License(服务器许可)
发布日期:2021-05-12 23:54:48 浏览次数:33 分类:精选文章

本文共 12878 字,大约阅读时间需要 42 分钟。

在Spring Boot项目中集成TrueLicense生成并验证服务器许可证,可以按照以下步骤实施:

1. 加载TrueLicense依赖

在项目的pom.xml中添加TrueLicense的依赖:

de.schlichtherle.truelicense
truelicense-core
1.33
provided

2. 配置生成许可证的参数

创建LicenseParam类,配置所有需要的参数:

package com.example.license;import com.fasterxml.jackson.databind.annotation.JsonFormat;import java.io.Serializable;import java.util.Date;public class LicenseParam implements Serializable {    private static final long serialVersionUID = -7793154252684580872L;    private String subject;    private String privateAlias;    private String keyPass;    private String storePass;    private String licensePath;    private String privateKeysStorePath;    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")    private Date issuedTime = new Date();    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")    private Date expiryTime;    private String consumerType = "user";    private Integer consumerAmount = 1;    private String description;    private LicenseCheckModel licenseCheckModel;    // setter和getter方法}

3. 创建自定义的硬件信息校验模型

定义LicenseCheckModel类,添加所需校验的硬件信息:

package com.example.license;import java.io.Serializable;import java.util.List;public class LicenseCheckModel implements Serializable {    private static final long serialVersionUID = 8600137500316662317L;    private List
ipAddress; private List
macAddress; private String cpuSerial; private String mainBoardSerial; // setter和getter方法}

4. 自定义LicenseManager进行自定义校验

继承LicenseManager并复写必要的方法:

public class CustomLicenseManager extends LicenseManager {    public CustomLicenseManager() {        super();    }    @Override    protected LicenseContent create(LicenseContent content, LicenseNotary notary) throws Exception {        initialize(content);        this.validateCreate(content);        final GenericCertificate certificate = notary.sign(content);        return getPrivacyGuard().cert2key(certificate);    }    @Override    protected void validate(LicenseContent content) throws LicenseContentException {        super.validate(content);        LicenseCheckModel expectedModel = (LicenseCheckModel) content.getExtra();        LicenseCheckModel serverModel = new LinuxServerInfos().getServerInfos();        if (expectedModel != null && serverModel != null) {            if (!checkIpAddress(expectedModel.ipAddress, serverModel.ipAddress)) {                throw new LicenseContentException("IP不在授权范围内");            }            if (!checkIpAddress(expectedModel.macAddress, serverModel.macAddress)) {                throw new LicenseContentException("MAC地址不在授权范围内");            }            if (!checkSerial(expectedModel.cpuSerial, serverModel.cpuSerial)) {                throw new LicenseContentException("CPU序列号不在授权范围内");            }            if (!checkSerial(expectedModel.mainBoardSerial, serverModel.mainBoardSerial)) {                throw new LicenseContentException("主板序列号不在授权范围内");            }        } else {            throw new LicenseContentException("无法获取服务器硬件信息");        }    }    private boolean checkIpAddress(List
expected, List
server) { if (server != null && expected != null) { for (String exp : expected) { if (server.contains(exp.trim())) { return true; } } } return false; } private boolean checkSerial(String expected, String server) { if (StringUtils.isNotBlank(expected) && StringUtils.isNotBlank(server)) { return expected.trim().equals(server.trim()); } return false; }}

5. 生成许可证文件

创建LicenseCreator类,负责生成许可证文件:

public class LicenseCreator {    private LicenseCreatorParam param;    public LicenseCreator(LicenseCreatorParam param) {        this.param = param;    }    public boolean generateLicense() {        try {            CustomLicenseManager licenseManager = new CustomLicenseManager(initLicenseParam());            LicenseContent licenseContent = initLicenseContent();            licenseManager.store(licenseContent, new File(param.getLicensePath()));            return true;        } catch (Exception e) {            logger.error("证书生成失败:" + param.toString(), e);            return false;        }    }    private LicenseParam initLicenseParam() {        Preferences preferences = Preferences.userNodeForPackage(LicenseCreator.class);        CipherParam cipherParam = new DefaultCipherParam(param.getStorePass());        KeyStoreParam keyStoreParam = new CustomKeyStoreParam(LicenseCreator.class, param.getPrivateKeysStorePath(), param.getPrivateAlias(), param.getStorePass(), param.getKeyPass());        return new DefaultLicenseParam(param.getSubject(), preferences, keyStoreParam, cipherParam);    }    private LicenseContent initLicenseContent() {        LicenseContent content = new LicenseContent();        content.setHolder(DEFAULT_HOLDER_AND_ISSUER);        content.setIssuer(DEFAULT_HOLDER_and_ISSUER);        content.setSubject(param.getSubject());        content.setIssued(param.getIssuedTime());        content.setNotBefore(param.getIssuedTime());        content.setNotAfter(param.getExpiryTime());        content.setConsumerType(param.getConsumerType());        content.setConsumerAmount(param.getConsumerAmount());        content.setDescription(param.getDescription());        content.setExtra(param.getLicenseCheckModel());        return content;    }    // 其他代码}

6. 创建生成许可证的接口

定义一个LicenseCreatorController,提供RESTful接口:

@RestControllerpublic class LicenseCreatorController {    @Value("${license.licensePath}")    private String licensePath;    @RequestMapping(value = "/generateLicense", produces = MediaType.APPLICATION_JSON_VALUE)    public Map
generateLicense(@RequestBody LicenseCreatorParam param) { Map
result = new HashMap<>(); if (StringUtils.isBlank(param.getLicensePath())) { param.setLicensePath(licensePath); } LicenseCreator licenseCreator = new LicenseCreator(param); boolean success = licenseCreator.generateLicense(); if (success) { result.put("status", "ok"); result.put("message", "许可证已成功生成,请检查生成路径:" + param.getLicensePath()); } else { result.put("status", "error"); result.put("message", "许可证文件生成失败,请检查日志或参数配置"); } return result; }}

7. 部署测试项目并生成许可证

部署测试项目ServerDemo,通过API接口获取硬件信息并生成许可证:

@SpringBootApplicationpublic class DemoApplication {    public static void main(String[] args) {        SpringApplication.run(DemoApplication.class, args);    }}@RestControllerpublic class LicenseGeneratorController {    @Value("${license.licenseTempPath}")    private String licenseTempPath;    @Value("${license.hardwareInfoUrl}")    private String hardwareInfoUrl;    @GetMapping("/getHardwareInfo")    public LicenseCheckModel getHardwareInfo(@RequestParam(required = false, name = "osName") String osName) {        if (StringUtils.isBlank(osName)) {            osName = System.getProperty("os.name").toLowerCase();        }        String пласти,也就是硬件信息集合.        AbstractServerInfos serverInfos = new LinuxServerInfos();        return serverInfos.getServerInfos();    }    @PostMapping("/generate")    public Map
generate(@RequestBody LicenseCreatorParam param) { Map
result = new HashMap<>(); if (StringUtils.isBlank(param.getLicensePath())) { param.setLicensePath(licenseTempPath); } LicenseCreator licenseCreator = new LicenseCreator(param); boolean success = licenseCreator.generateLicense(); if (success) { result.put("status", "success"); result.put("message", "许可证已生成,路径为:" + param.getLicensePath()); } else { result.put("status", "error"); result.put("message", "许可证生成失败,请检查配置"); } return result; }}

8. 集成许可证校验

创建LicenseVerify类,负责校验许可证并安装:

public class LicenseVerify {    public LicenseVerify() {        super();    }    public LicenseContent install(LicenseVerifyParam param) throws Exception {        LicenseManager manager = LicenseManagerHolder.getInstance(formatParameters(param));        manager.uninstall();        LicenseContent content = manager.install(new File(param.getLicensePath()));        logger.info(" Installed successfully, valid until: {}, expires at: {}", content.getNotBefore(), content.getNotAfter());        return content;    }    public boolean verify() {        LicenseManager manager = LicenseManagerHolder.getInstance(null);        try {            LicenseContent content = manager.verify();            logger.info(" Verified successfully; valid until: {}, expires at: {}", content.getNotBefore(), content.getNotAfter());            return true;        } catch (Exception e) {            logger.error("Verification failed!", e);            return false;        }    }    private LicenseParam formatParameters(LicenseVerifyParam param) {        return new DefaultLicenseParam(                param.getSubject(),                 preferences,                keyStoreParam,                cipherParam        );    }}

9. 自动安装许可证

创建LicenseCheckListener,在项目启动时安装许可证:

@SpringBootApplicationpublic class LicenseApplication extends Application {    public static void main(String[] args) {        SpringApplication.run(LicenseApplication.class, args);    }    @Value("${license.clientОВерID_BOOL}")    private boolean enabled;    @Value("${license.licensePath}")    private String licensePath;    @Value("${license.publicKeysStorePath}")    private String publicStorePath;    @Value("${license.subject}")    private String subject;    @Value("{license.publicAlias}")    private String publicAlias;    @Value("{license.storePass}")    private String storePass;    @Component    public class LicenseCheckListener implements ApplicationListener {        @Override        public void onApplicationEvent(ContextRefreshedEvent event) {            if (enabled) {                logger.info("Installing license on application refresh...");                LicenseVerifyParam param = new LicenseVerifyParam()                        .setSubject(subject)                        .setPublicAlias(publicAlias)                        .setStorePass(storePass)                        .setLicensePath(licensePath)                        .setPublicKeysStorePath(publicStorePath);                if (param.getLicensePath() != null) {                    LicenseVerify licenseVerify = new LicenseVerify();                    LicenseContent content = licenseVerify.install(param);                    logger.info("License successfully installed. Valid until: {}, expires at: {}", content.getNotBefore(), content.getNotAfter());                }            }        }    }}

10. 集成许可证拦截器

创建LicenseCheckInterceptor,在每次请求时校验许可证:

@EnableWebMvcpublic class LicenseInterceptor extends HandlerInterceptorAdapter {    @Autowired    LicenseVerify licenseVerify;    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        logger.entry();        LicenseVerify verify = new LicenseVerify();        if (!verify.verify()) {            response.sendRedirect("/login");            return false;        }        return true;    }}

11. 配置Redis缓存(可选)

为了提升性能,可以将许可证校验结果存储在Redis中:

@Configurationpublic class LicenseConfig {    @Value("${license.redis.isEnabled}")    private boolean enableRedis;    @Condition(!enableRedis)    public LicenseVerify664ependencies() {        return newisque    }    @Condition(EnableRedis.class)    public LicenseRedisConfig config() {        return new LicenseRedisConfig();    }}public class LicenseRedisConfig {    @Autowired    LicenseVerify licenseVerify;    @Autowired    CacheConfig cacheConfig;    @Bean    public CacheEvictionHandler handleCacheEvictions() {        return new CacheEvictionHandler();    }}

12. 提示验证

在登录页面添加判断逻辑,提示无效的许可证:

    Login    

Login

register now

13. 使用命令生成密钥库

使用keytool生成密钥库:

keytool -genkeypair -keysize 1024 -validity 365 -alias "privateKey" -keystore privateKeys.keystore -storepass "public_password1234" -keypass "private_password1234" -dname "CN=localhost, OU=MyApplication, O=MyCompany, L=Location, ST=State, C=Country"keytool -exportcert -alias "privateKey" -keystore privateKeys.keystore -storepass "public_password1234" -file cert.pemkeytool -import -alias "publicCert" -file cert.pem -keystore publicCerts.keystore -storepass "public_password1234"

14. 部署项目并测试

将War文件部署到应用服务器中,并访问登录页面进行测试,确保每次登录都自动校验许可证。

15. 权力平衡

确保所有OTC相关的日志都被正确记录,并且能方便地定位问题。

16. 上线与维护

部署完成后,持续监控许可证的有效期和硬件信息变化,确保许可证能够及时更新和管理。

通过以上步骤,可以实现以TrueLicense为基础,生成并验证服务器许可证的过程,确保客户端的合法性和项目的安全性。

上一篇:ProGuard对java jar包实现混淆加密
下一篇:vuex理论与工程实践后的心得总结

发表评论

最新留言

很好
[***.229.124.182]2025年04月30日 01时13分46秒