首页 » Java » Spring » 正文

Spring Boot项目中使用 TrueLicense 生成和验证License(服务器许可)

一 简介

License,即版权许可证,一般用于收费软件给付费用户提供的访问许可证明。根据应用部署位置的不同,一般可以分为以下两种情况讨论:

  • 应用部署在开发者自己的云服务器上。这种情况下用户通过账号登录的形式远程访问,因此只需要在账号登录的时候校验目标账号的有效期、访问权限等信息即可。
  • 应用部署在客户的内网环境。因为这种情况开发者无法控制客户的网络环境,也不能保证应用所在服务器可以访问外网,因此通常的做法是使用服务器许可文件,在应用启动的时候加载证书,然后在登录或者其他关键操作的地方校验证书的有效性。

注:限于文章篇幅,这里只讨论代码层面的许可限制,暂不考虑逆向破解等问题。此外,在下面我只讲解关键代码实现,完整代码可以参考:https://gitee.com/zifangsky/LicenseDemo

二 使用 TrueLicense 生成License

(1)使用Spring Boot构建测试项目ServerDemo,用于为客户生成License许可文件:

注:这个完整的Demo项目可以参考:https://gitee.com/zifangsky/LicenseDemo/tree/master/ServerDemo

i)在pom.xml中添加关键依赖:

ii)校验自定义的License参数:

TrueLicense的 de.schlichtherle.license.LicenseManager 类自带的verify方法只校验了我们后面颁发的许可文件的生效和过期时间,然而在实际项目中我们可能需要额外校验应用部署的服务器的IP地址、MAC地址、CPU序列号、主板序列号等信息,因此我们需要复写框架的部分方法以实现校验自定义参数的目的。

首先需要添加一个自定义的可被允许的服务器硬件信息的实体类(如果校验其他参数,可自行补充):

其次,添加一个License生成类需要的参数:

添加抽象类AbstractServerInfos,用户获取服务器的硬件信息:

获取客户Linux服务器的基本信息:

获取客户Windows服务器的基本信息:

注:这里使用了模板方法模式,将不变部分的算法封装到抽象类,而基本方法的具体实现则由子类来实现。更多内容可以参考我之前写的文档:模板方法模式

自定义LicenseManager,用于增加额外的服务器硬件信息校验:

最后是License生成类,用于生成License证书:

iii)添加一个生成证书的Controller:

这个Controller对外提供了两个RESTful接口,分别是「获取服务器硬件信息」和「生成证书」,示例代码如下:

(2)使用JDK自带的 keytool 工具生成公私钥证书库:

假如我们设置公钥库密码为:public_password1234,私钥库密码为:private_password1234,则生成命令如下:

上述命令执行完成之后,会在当前路径下生成三个文件,分别是:privateKeys.keystore、publicCerts.keystore、certfile.cer。其中文件certfile.cer不再需要可以删除,文件privateKeys.keystore用于当前的 ServerDemo 项目给客户生成license文件,而文件publicCerts.keystore则随应用代码部署到客户服务器,用户解密license文件并校验其许可信息。

(3)为客户生成license文件:

将 ServerDemo  项目部署到客户服务器,通过以下接口获取服务器的硬件信息(等license文件生成后需要删除这个项目。当然也可以通过命令手动获取客户服务器的硬件信息,然后在开发者自己的电脑上生成license文件):

注:上图使用的是Firefox的RESTClient插件

然后生成license文件:

请求时需要在Header中添加一个 Content-Type ,其值为:application/json;charset=UTF-8。参数示例如下:

如果请求成功,那么最后会在 licensePath 参数设置的路径生成一个 license.lic 的文件,这个文件就是给客户部署代码的服务器许可文件。

三 给客户部署的应用中添加License校验

(1)使用Spring Boot构建测试项目ServerDemo,用于模拟给客户部署的应用:

注:这个完整的Demo项目可以参考:https://gitee.com/zifangsky/LicenseDemo/tree/master/ClientDemo

(2)添加License校验类需要的参数:

然后再添加License校验类:

(3)添加Listener,用于在项目启动的时候安装License证书:

注:上面代码使用参数信息如下所示:

(4)添加拦截器,用于在登录的时候校验License证书:

(5)添加登录页面并测试:

添加一个登录页面,可以在license校验失败的时候给出错误提示:

i)启动项目,可以发现之前生成的license证书可以正常使用:

这时访问 http://127.0.0.1:7080/login ,可以正常登录:

ii)重新生成license证书,并设置很短的有效期。

iii)重新启动ClientDemo,并再次登录,可以发现爆以下提示信息:

至此,关于使用 TrueLicense 生成和验证License就结束了,文章中没有说到的类可以自行参考示例源码,谢谢阅读。

本文共 21 个回复

  • Eric 2020/07/02 10:53

    客户端一直无法获取到license里面的ip、mac等信息,expectedCheckModel为null怎么处理, 或者说,哪里获取license里面信息

    • admin 博主 2020/07/03 14:04

      @ Eric 可能是你加密那个服务和验证那个服务的LicenseCheckModel类不在同一个包路径下面,所以最后XML反序列化失败。

  • chen 2020/03/16 16:44

    //root application context 没有parent ApplicationContext context = event.getApplicationContext().getParent(); if(context == null){ 请问为什么要这样判断 感谢

  • 拾光 2020/02/20 17:01

    楼主你好,我在安装证书的时候一直出错de.schlichtherle.license.LicenseContentException: exc.licenseIsNotYetValid,两天了不知道怎么办

    • admin 博主 2020/02/20 17:47

      @ 拾光 仔细看文章中所有步骤,检查下是不是自己哪个步骤遗漏或者搞错了,特别是生效时间这种字段。

  • alsk000999 2020/02/11 15:25

    麻烦问一下博主 de.schlichtherle.license.IllegalPasswordException: null 这个问题如何解决呐 已经生成了公钥 私钥

  • change 2019/12/13 16:36

    你好,启动报C:\Users\zifangsky\Desktop\license_demo\license.lic (系统找不到指定的路径。) 请问这个license.lic是从哪来的呀,我看你的博客jdk生成的文件没有这个呀,我是少了什么步骤吗。

    • admin 博主 2019/12/13 16:42

      @ change 那个是license授权文件,你仔细看文章中的“(3)为客户生成license文件”这一小节

  • 球形闪电z 2019/12/08 12:52

    o(╥﹏╥)o 总是生成失败,debug半天也没看出来。。。报错 de.schlichtherle.xml.PersistenceServiceException: java.lang.Exception: XMLEncoder: discarding statement XMLEncoder.writeObject(LicenseContent);

  • cat 2019/06/11 17:49

    楼主 在项目加mac地址该怎么用啊 :?:

  • ipodao 2019/04/24 21:26

    楼主您好!我这里也是代码运行起来了,在换到其他的项目的时候复用了license 但是在:CustomLicenseManager 类里的validate 方法 获取不到: LicenseCheckModel expectedCheckModel = (LicenseCheckModel) content.getExtra(); 显示为null ,但是在的demo里又是可以获取到的,我开了debug模式,一步步走,也没有看懂例子里是怎么获取到值的。

    • admin 博主 2019/04/24 22:20

      @ ipodao 可能是你加密那个服务和验证那个服务的LicenseCheckModel类不在同一个包路径下面,所以最后XML反序列化失败。

      • ipodao 2019/04/24 22:31

        @ admin 是的,我刚刚一步步debug看到了问题,是因为我使用了之前demo的key ,在新的代码里面没有: 等这些信息,包的路径 不对 希望看到的人不要再走我的坑了, 找到问题的的地方是:CustomLicenseManager.load 打个断点就知道了,详细内容可以看解析的xml 内容。 这个问题让我找了一下午,白白浪费了大好时光。 多谢博主,文章真的很好! :cool:

        • foo 2019/06/18 19:50

          @ ipodao 什么意思,我恁是没有看明白 :???:

        • allenliu574 2020/06/23 09:43

          @ ipodao 你好,我也遇到了同样的问题,请问你最后怎么解决了呢?谢谢!

  • Dennis 2019/03/27 11:51

    楼主您好!全按照你文章的内容,代码都运行起来了。 我用不符合 Server 的 Mac Address 和 IP 生成的 License , Client 在运行起来后,verify 一直是通过的. 请问你有遇到类似的情形吗?谢谢!

    • admin 博主 2019/03/27 14:08

      @ Dennis 第一,你生成license时需要用Client所在服务器的硬件信息。第二,校验一直通过,你可以在client的相关代码打个断点,看看有没有执行license解密、校验等相关代码逻辑。

发表评论

*