SpringBoot实现License认证(只校验有效期)

这篇具有很好参考价值的文章主要介绍了SpringBoot实现License认证(只校验有效期)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、License介绍

License也就是版权许可证书,一般用于收费软件给付费用户提供的访问许可证明

应用场景

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

License授权原理

  • 使用开源的证书管理引擎TrueLicense
    1. 生成密钥对,使用Keytool生成公私钥证书库
    2. 授权者保留私钥,使用私钥和使用日期生成证书license
    3. 公钥与生成的证书给使用者(放在验证的代码中使用),验证证书license是否在有效期内

二、授权者生成密钥对

  • 需要关注以及修改的参数:storepass(私钥库的密码)、keypass(私钥的密码)
  • 其他参数使用默认值即可,validity(私钥的有效期)设置十年就可以,因为以后会通过私钥和证书有效期生成证书license
## 1. 生成私匙库
# validity:私钥的有效期(单位:天)
# alias:私钥别称
# keystore: 私钥库文件名称(生成在当前目录)
# storepass:私钥库的密码(获取keystore信息所需的密码) 
# keypass:私钥的密码
# dname 证书个人信息
# 	CN 为你的姓名
#	OU 为你的组织单位名称
#	O 为你的组织名称
#	L 为你所在的城市名称
#	ST 为你所在的省份名称
#	C 为你的国家名称 或 区号
keytool -genkeypair -keysize 1024 -validity 3650 -alias "privateKey" -keystore "privateKeys.keystore" -storepass "public_password1234" -keypass "private_password1234" -dname "CN=localhost, OU=localhost, O=localhost, L=SH, ST=SH, C=CN"

## 2. 把私匙库内的公匙导出到一个文件当中
# alias:私钥别称
# keystore:私钥库的名称(在当前目录查找)
# storepass: 私钥库的密码
# file:证书名称
keytool -exportcert -alias "privateKey" -keystore "privateKeys.keystore" -storepass "public_password1234" -file "certfile.cer"

## 3. 再把这个证书文件导入到公匙库
# alias:公钥别称
# file:证书名称
# keystore:公钥文件名称(生成在当前目录)
# storepass:私钥库的密码
keytool -import -alias "publicCert" -file "certfile.cer" -keystore "publicCerts.keystore" -storepass "public_password1234"

上述命令执行完成后会在当前目录生成三个文件:

  1. certfile.cer 认证证书文件,已经没用了,可以删除
  2. privateKeys.keystore 私钥文件,自己保存,以后用于生成license.lic证书
  3. publicKeys.keystore 公钥文件,以后会和license.lic证书一起放到使用者项目里

三、授权者生成license.lic证书

pom.xml

<!-- License -->
<dependency>
    <groupId>de.schlichtherle.truelicense</groupId>
    <artifactId>truelicense-core</artifactId>
    <version>1.33</version>
</dependency>

1、License生成类

import de.schlichtherle.license.*;
import lombok.extern.slf4j.Slf4j;
import javax.security.auth.x500.X500Principal;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.prefs.Preferences;

@Slf4j
public class LicenseCreator {
    private final static X500Principal DEFAULT_HOLDER_AND_ISSUER = 
    	new X500Principal("CN=localhost, OU=localhost, O=localhost, L=SH, ST=SH, C=CN");

    /**
     * @description main方法生成license文件
     * @author xuchang
     * @date 2024/3/4 15:51:14
     */
    public static void main(String[] args) throws IOException {
        LicenseCreatorParam param = new LicenseCreatorParam();
        // 证书主题
        param.setSubject("license");
        // 密钥别称
        param.setPrivateAlias("privateKey");
        // 私钥密码
        param.setKeyPass("private_password1234");
        // 私钥库的密码
        param.setStorePass("public_password1234");
        // 证书生成路径
        param.setLicensePath("/Users/xuchang/Documents/license/license.lic");
        // 私钥存储路径
        param.setPrivateKeysStorePath("/Users/xuchang/Documents/license/privateKeys.keystore");
        // 证书生成时间-当前时间
        param.setIssuedTime(new Date());
        LocalDateTime localDateTime = LocalDateTime.of(2024, 12, 31, 23, 59, 59);
        Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        // 证书过期时间-2024年12月31日23:59:59
        param.setExpiryTime(date);
        // 用户类型
        param.setConsumerType("user");
        // 用户数量
        param.setConsumerAmount(1);
        // 证书描述
        param.setDescription("证书描述信息");
        // 生成证书
        LicenseCreator licenseCreator = new LicenseCreator();
        licenseCreator.generateLicense(param);
    }

    // 生成License证书
    public void generateLicense(LicenseCreatorParam param) {
        try {
            LicenseManager licenseManager = new LicenseManager(initLicenseParam(param));
            LicenseContent licenseContent = initLicenseContent(param);
            licenseManager.store(licenseContent, new File(param.getLicensePath()));
        } catch (Exception e) {
            log.error("证书生成失败", e);
        }
    }

    // 初始化证书生成参数
    private static LicenseParam initLicenseParam(LicenseCreatorParam param) {
        Preferences preferences = Preferences.userNodeForPackage(LicenseCreator.class);
        // 设置对证书内容加密的秘钥
        CipherParam cipherParam = new DefaultCipherParam(param.getStorePass());
        // 自定义KeyStoreParam
        KeyStoreParam privateStoreParam = new CustomKeyStoreParam(LicenseCreator.class
                , param.getPrivateKeysStorePath()
                , param.getPrivateAlias()
                , param.getStorePass()
                , param.getKeyPass());

        // 组织License参数
        return new DefaultLicenseParam(param.getSubject()
                , preferences
                , privateStoreParam
                , cipherParam);
    }

    // 设置证书生成正文信息
    private static LicenseContent initLicenseContent(LicenseCreatorParam param) {
        LicenseContent licenseContent = new LicenseContent();
        licenseContent.setHolder(DEFAULT_HOLDER_AND_ISSUER);
        licenseContent.setIssuer(DEFAULT_HOLDER_AND_ISSUER);
        licenseContent.setSubject(param.getSubject());
        licenseContent.setIssued(param.getIssuedTime());
        licenseContent.setNotBefore(param.getIssuedTime());
        licenseContent.setNotAfter(param.getExpiryTime());
        licenseContent.setConsumerType(param.getConsumerType());
        licenseContent.setConsumerAmount(param.getConsumerAmount());
        licenseContent.setInfo(param.getDescription());
        return licenseContent;
    }
}

License生成类需要的参数类

@Data
public class LicenseCreatorParam {
    /**
     * 证书subject
     */
    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;

    /**
     * 证书失效时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date expiryTime;

    /**
     * 用户类型
     */
    private String consumerType;

    /**
     * 用户数量
     */
    private Integer consumerAmount;

    /**
     * 描述信息
     */
    private String description;
}

自定义KeyStoreParam

public class CustomKeyStoreParam extends AbstractKeyStoreParam {
    private final String storePath;
    private final String alias;
    private final String storePwd;
    private final String keyPwd;

    public CustomKeyStoreParam(Class clazz, String resource, String alias, String storePwd, String keyPwd) {
        super(clazz, resource);
        this.storePath = resource;
        this.alias = alias;
        this.storePwd = storePwd;
        this.keyPwd = keyPwd;
    }

    @Override
    public String getAlias() {
        return alias;
    }

    @Override
    public String getStorePwd() {
        return storePwd;
    }

    @Override
    public String getKeyPwd() {
        return keyPwd;
    }

    @Override
    public InputStream getStream() throws IOException {
        return Files.newInputStream(Paths.get(storePath));
    }
}

2、main方法生成license.lic注意事项

java springboot lisence,java相关,spring boot,https,ssl

  • 以上都是授权者需要做的,下面说下使用者需要的配置

四、使用者配置

pom.xml

<!-- License -->
<dependency>
    <groupId>de.schlichtherle.truelicense</groupId>
    <artifactId>truelicense-core</artifactId>
    <version>1.33</version>
</dependency>

1、License校验类

@Slf4j
public class LicenseVerify {
    // 安装License证书
    public synchronized LicenseContent install(LicenseVerifyParam param) {
        LicenseContent result = null;
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 1. 安装证书
        try {
            LicenseManager licenseManager = LicenseManagerHolder.getInstance(initLicenseParam(param));
            licenseManager.uninstall();
            result = licenseManager.install(new File(param.getLicensePath()));
            log.info(MessageFormat.format("证书安装成功,证书有效期:{0} - {1}", 
            	format.format(result.getNotBefore()), format.format(result.getNotAfter())));
        } catch (Exception e) {
            log.error("证书安装失败: {}", e.getMessage());
        }
        return result;
    }

    // 校验License证书
    public boolean verify() {
        LicenseManager licenseManager = LicenseManagerHolder.getInstance(null);
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 2. 校验证书
        try {
            LicenseContent licenseContent = licenseManager.verify();
            log.info(MessageFormat.format("证书校验通过,证书有效期:{0} - {1}", 
            	format.format(licenseContent.getNotBefore()), format.format(licenseContent.getNotAfter())));
            return true;
        } catch (Exception e) {
            log.error("证书校验失败: {}", e.getMessage());
            return false;
        }
    }

    // 初始化证书生成参数
    private LicenseParam initLicenseParam(LicenseVerifyParam param) {
        Preferences preferences = Preferences.userNodeForPackage(LicenseVerify.class);
        CipherParam cipherParam = new DefaultCipherParam(param.getStorePass());
        KeyStoreParam publicStoreParam = new CustomKeyStoreParam(LicenseVerify.class
                , param.getPublicKeysStorePath()
                , param.getPublicAlias()
                , param.getStorePass()
                , null);
        return new DefaultLicenseParam(param.getSubject()
                , preferences
                , publicStoreParam
                , cipherParam);
    }
}

License校验类需要的参数

@Data
public class LicenseVerifyParam {
    /**
     * 证书subject
     */
    private String subject;

    /**
     * 公钥别称
     */
    private String publicAlias;

    /**
     * 访问公钥库的密码
     */
    private String storePass;

    /**
     * 证书生成路径
     */
    private String licensePath;

    /**
     * 密钥库存储路径
     */
    private String publicKeysStorePath;
}

自定义KeyStoreParam(与授权者一样)

public class CustomKeyStoreParam extends AbstractKeyStoreParam {
    private final String storePath;
    private final String alias;
    private final String storePwd;
    private final String keyPwd;

    public CustomKeyStoreParam(Class clazz, String resource,String alias,String storePwd,String keyPwd) {
        super(clazz, resource);
        this.storePath = resource;
        this.alias = alias;
        this.storePwd = storePwd;
        this.keyPwd = keyPwd;
    }

    @Override
    public String getAlias() {
        return alias;
    }

    @Override
    public String getStorePwd() {
        return storePwd;
    }

    @Override
    public String getKeyPwd() {
        return keyPwd;
    }

    @Override
    public InputStream getStream() throws IOException {
        return Files.newInputStream(Paths.get(storePath));
    }
}

LicenseManager的单例

public class LicenseManagerHolder {
    private static volatile LicenseManager LICENSE_MANAGER;
    public static LicenseManager getInstance(LicenseParam param){
        if(LICENSE_MANAGER == null){
            synchronized (LicenseManagerHolder.class){
                if(LICENSE_MANAGER == null){
                    LICENSE_MANAGER = new LicenseManager(param);
                }
            }
        }
        return LICENSE_MANAGER;
    }
}

2、项目启动时安装证书

  • application.poperties配置
#License配置
# 与创建license.lic设置的值一样
license.subject=license
# 与生成密钥对的公钥别称一样
license.publicAlias=publicCert
# 私钥库的密码
license.storePass=public_password1234
  • license.lic证书和publicCerts.keystore放入resources资源目录下

java springboot lisence,java相关,spring boot,https,ssl

  • springboot项目启动后执行操作
@Slf4j
@Component
public class LicenseCheckRunner implements ApplicationRunner {
    /**
     * 证书subject
     */
    @Value("${license.subject}")
    private String subject;

    /**
     * 公钥别称
     */
    @Value("${license.publicAlias}")
    private String publicAlias;

    /**
     * 访问公钥库的密码
     */
    @Value("${license.storePass}")
    private String storePass;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("++++++++ 开始安装证书 ++++++++");
        LicenseVerifyParam param = new LicenseVerifyParam();
        param.setSubject(subject);
        param.setPublicAlias(publicAlias);
        param.setStorePass(storePass);
        // 相对路径resources资源目录
        String resourcePath = getClass().getClassLoader().getResource("").getPath();
        // 证书地址
        param.setLicensePath(resourcePath + "license.lic");
        // 公钥地址
        param.setPublicKeysStorePath(resourcePath + "publicCerts.keystore");
        // 安装证书
        LicenseVerify licenseVerify = new LicenseVerify();
        licenseVerify.install(param);
        log.info("++++++++ 证书安装结束 ++++++++");
    }
}
  • 如果想要当前配置作为公共类,对于多个微服务,只想要一个服务resources/license下配置证书和公钥
  • 获取公共服务里证书和公钥的输入流,然后拷贝到当前服务下

java springboot lisence,java相关,spring boot,https,ssl

  • 启动安装成功

java springboot lisence,java相关,spring boot,https,ssl

  • 启动安装失败(证书过期)

java springboot lisence,java相关,spring boot,https,ssl

3、设置拦截器

配置拦截器

@Slf4j
public class LicenseCheckInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        LicenseVerify licenseVerify = new LicenseVerify();
        // 校验证书是否有效
        boolean verifyResult = licenseVerify.verify();
        if (verifyResult) {
            return true;
        } else {
            response.setCharacterEncoding("utf-8");
            Map<String, String> result = new HashMap<>(1);
            result.put("result", "您的证书无效,请核查服务器是否取得授权或重新申请证书!");
            response.getWriter().write(JSON.toJSONString(result));
            return false;
        }
    }
}

注册拦截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LicenseCheckInterceptor());
    }
}
  • 证书有效期内请求接口

java springboot lisence,java相关,spring boot,https,ssl

  • 证书过期请求接口

java springboot lisence,java相关,spring boot,https,ssl文章来源地址https://www.toymoban.com/news/detail-853555.html

到了这里,关于SpringBoot实现License认证(只校验有效期)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 安装 .net framwork失败,提示证书不在有效期内

    适用于 Windows 的 Microsoft .NET Framework 4.8 脱机安装程序 https://support.microsoft.com/zh-cn/topic/%E9%80%82%E7%94%A8%E4%BA%8E-windows-%E7%9A%84-microsoft-net-framework-4-8-%E8%84%B1%E6%9C%BA%E5%AE%89%E8%A3%85%E7%A8%8B%E5%BA%8F-9d23f658-3b97-68ab-d013-aa3c3e7495e0 点击上面链接离线安装

    2024年02月15日
    浏览(36)
  • Istio实战(十二)-Istio 延长自签发证书的有效期

            因为历史原因,Istio 的自签发证书只有一年的有效期。如果你选择使用 Istio 的自签发证书,就需要在它们过期之前订好计划进行根证书的更迭。根证书过期可能会导致集群范围内的意外中断。         我们认为每年更换根证书和密钥是一个安全方面的最佳实践

    2024年02月06日
    浏览(34)
  • 校准曲线、标准曲线、工作曲线区别:点个数、曲线评价、有效期、模型

            最近看到一篇叙述校准曲线、标准曲线、工作曲线区别的文章,但可惜的是查看收费,扪心自问,还真容易分不清,特此写下此文作为后续查看使用。 一、基本概念 校准曲线:包括标准曲线和工作曲线。在规定条件下,表示被测量值与仪器仪表实际测得值之间关系

    2024年02月03日
    浏览(41)
  • Windows 11设置登录账户密码有效期或密码永不过期的方法

    目录 文章目录 序言 网上的方法(不管用) 本地组策略编辑器 自己的方法(亲测有效) 示例命令一:添加本地账户 示例命令二:查看本地账户默认过期时间 示例命令三(推荐):设置本地账户密码永不过期 示例命令四:设置系统策略中默认密码最长时间为无限制 示例命令

    2024年02月16日
    浏览(37)
  • CentOS 7 服务器上创建新用户及设置用户密码有效期

    一、创建用户 1、以 root 用户身份登录到 CentOS 服务器 2、运行以下命令以创建新用户: 3、运行以下命令以设置新用户的密码: 4、如果您希望将新创建的用户添加到用户组中,可以通过以下命令添加: 5、运行以下命令以查看新用户所属的用户组: 6、操作 二、设置用户密码

    2024年02月03日
    浏览(57)
  • openGauss学习笔记-114 openGauss 数据库管理-设置安全策略-设置帐号有效期

    114.1 注意事项 创建新用户时,需要限制用户的操作期限(有效开始时间和有效结束时间)。 不在有效操作期内的用户需要重新设定帐号的有效操作期。 114.2 操作步骤 以操作系统用户omm登录数据库主节点。 使用如下命令连接数据库。 postgres为需要连接的数据库名称,8000为数

    2024年02月05日
    浏览(59)
  • win7 安装ArcMap10.7提示下载Microsoft.NET Framework 4.5,安装过程中提示:安尚未成功,根据当前系统时钟或签名文件中的时间戳验证时要求的证书不在有效期内。

    win7 安装ArcMap10.7提示下载Microsoft.NET Framework 4.5,安装过程中提示:安尚未成功,根据当前系统时钟或签名文件中的时间戳验证时要求的证书不在有效期内。 键盘快捷键win+r,在命令提示符里输入cmd,输入winver,并回车,可以查看对应的版本。 32位系统补丁下载地址: https://

    2024年02月05日
    浏览(99)
  • springboot整合Sa-Token实现登录认证和权限校验(万字长文)

    目前在国内的后端开发中,常用的安全框架有spring security、shiro。现在,介绍一款由国人开发的安全框架Sa-Token。这个框架完全由国人开发,所提供的Api文档和一些设置都是比较符合国人的开发习惯的,本次就来介绍一下如何在spring boot框架中整合Sa-Token框架,以实现我们最常

    2024年04月27日
    浏览(43)
  • 3-2. SpringBoot项目集成【用户身份认证】实战 【实战核心篇】基于JWT生成和校验Token

    书接上文 技术选型篇,我们做了【用户身份认证】的技术选型说明,对基于 Session、Token、JWT 的方案进行了详细的对比分析,详细说明了它们都是什么和各自的优缺点!这些是实战的基础,还没看过的同学,建议先看上文。最终采用的是目前流行的 基于JWT的Token用户身份认证

    2023年04月08日
    浏览(48)
  • 最详细的SpringBoot实现接口校验签名调用

    代码地址:GitHub - passerbyYSQ/DemoRepository: 各种开发小demo 概念 开放接口 验签 接口验签调用流程 1. 约定签名算法 2. 颁发非对称密钥对 3. 生成请求参数签名 4. 请求携带签名调用 代码设计 1. 签名配置类 2. 签名管理类 3. 自定义验签注解 4. AOP实现验签逻辑 5. 解决请求体只能读取一

    2024年02月09日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包