基础框架-文档中心基础框架-文档中心
使用指南
公共组件
开发测试
  • 微服务框架
  • Vue3框架
  • 项目实践
更新日志
  • V3.3.0
  • V3.2.6
  • V3.2.5
  • V3.2.4
  • V3.1.0
  • V2.2.x
  • V2.1.0
  • V2.0.0
  • V1.2.1
  • V1.1.1
使用指南
公共组件
开发测试
  • 微服务框架
  • Vue3框架
  • 项目实践
更新日志
  • V3.3.0
  • V3.2.6
  • V3.2.5
  • V3.2.4
  • V3.1.0
  • V2.2.x
  • V2.1.0
  • V2.0.0
  • V1.2.1
  • V1.1.1
  • 后端组件

    • waf-license-产品证书授权
    • waf-calcite-动态数据管理
    • 消息中心组件
    • 调度任务组件
    • xxl-job 安装使用
    • API服务
    • 全文检索
  • 前端组件

    • 分页组件
    • 数据字典组件
    • 业务字典组件
    • 人员选择组件
    • 组织机构选择组件
    • 文件上传组件
    • 第三方应用集成

waf-license-产品证书授权

在我们开发的产品正式发布时,需要提供给客户试用或者正常采购时,需要提供产品的使用期限、IP地址、MAC地址、CPU序列号、主板序列号等进行授权与认证。

临时试用: 提供一个1个月或3个月的试用期的证书

正式采购: 根据采购模式,可以提供无期限或绑定IP地址、MAC地址、CPU序列号、主板序列号等方式进行限制。

在公司开发的产品像数据资产平台、数据集成交换平台、数个创平台等,只需要添加证书授权组件,设置拦截器就可实现证书的授权,不需要修改产品任何代码。

0、版本发布

2.0.1/1.0.1

2025-11-01 发布1.0.1版本(JDK1.8)

2025-11-01 发布2.0.1版本(JDK17)

功能列表

  • 支持多应用证书认证同时启动(即多个使用证书授权的应用同时启动,证书验证被覆盖问题修复
waf:
  license:
    # 应用启动类路径(注:如多个应用启动类路径一样,请进行调整)
    appClass: ${LICENSE_APP_CLASS:com.wiseda.waf.WafApplication}

因windos下,会在注册表:HKEY_CURRENT_USER\Software\JavaSoft\Prefs\路径下,根据appClass配置的包路径生成license key的存放路径。

异常信息如下:

# 2025-11-01 21:51:24,651 ERROR 6596 --- [http-nio-8081-exec-5] com.wiseda.waf.license.LicenseVerify    [verify,70] : 证书校验失败!
# javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.

2.0.0/1.0.0

2025-08-25 发布1.0.0版本(JDK1.8)

2025--08-25 发布2.0.0版本(JDK17)

功能列表

  • 产品或项目支持证书授权认证
  • 可支持有效期限、IP、MAC地址、CPU序列号等验证

1、产品证书组件

在进行产品证书认证时,由发证方根据提供的信息,如使用期限,限制的IP、MAC地址来制件证书文件,客户端证书包括两个文件:

license.lic:证书信息,包含使用期限、限制的IP列表、MAC地址列表

publicCerts.keystore:验证客户端License(容器中使用的OpenJDK,需要通过容器中的keytool来生成privateKeys.keystore、publicCerts.keystore,不然启动会出现java.io.IOException: Invalid keystore format异常)

1.1、pom.xml 配置

在pom.xml中添加license-client客户端,注意版本号请采用最新版本。

JDK 8: 最新版本1.0.0

JDK17: 最新版本2.0.0

<!--license JDK8 客户端-->
<dependency>
    <groupId>com.wiseda.waf</groupId>
    <artifactId>waf-license-client</artifactId>
    <version>1.0.0</version>
</dependency>

<!--license JDK17 客户端-->
<dependency>
    <groupId>com.wiseda.waf</groupId>
    <artifactId>waf-license-client</artifactId>
    <version>2.0.0</version>
</dependency>

1.2、application.yml 配置

exclusions:/license/* (这里如果有其他,一并配置,该配置用于通过API来查看服务器信息、证书有效期、在线更新证书)

subject:waf_license(以应用英文简称命名,以发证配置为准)

publicAlias:publicCert(证书别名,以发证配置为准)

storePass:获取publicCerts.keystore 密钥库密码(以发证配置为准)

licensePath:证书文件路径(发证方提供)

publicKeysStorePath:密钥库存储路径(发证方提供)

waf:
  server:
    # shiro匿名访问的地址配置,多个以逗号分隔
    exclusions: ${WAF_SERVER_EXCLUSIONS:/license/*}
  license:
    subject: ${LICENSE_SUBJECT:waf_license}
    publicAlias: ${LICENSE_PUBLIC_ALIAS:publicCert}
    storePass: ${LICENSE_STORE_PASS:******}
    licensePath: ${LICENSE_LICENSE_PATH:/opt/waf/license/license.lic}
    publicKeysStorePath: ${LICENSE_STORE_PATH:/opt/waf/license/publicCerts.keystore}    

1.3、拦截器配置

代码示例,如产品本身已经有拦截器的config,只要添加LicenseCheckInterceptor,配置如果规则即可。

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    /**
     * 添加拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LicenseCheckInterceptor())
                .addPathPatterns("/**")
                // 排序license接口,用于证书过期后能刷新更新证书(根据业务自行细化,如容器化部署也可以移除过滤)
                .excludePathPatterns("/license/**");
    }
}

2、证书验证

证书所有配置都验证成功后,启动日志中将输出证书的有效期限,如果证书过期或其他认证失败,产品将无法启动。

正常启动完成,后续的访问授权,还是产品原来的逻辑,根据配置的过滤规则来进行拦截验证,验证的过程大概在8-9毫秒左右,基本上可以忽略,不影响业务功能的正常响应。

[main] INFO  c.w.w.l.c.LicenseCheckListener - [onApplicationEvent,33] - ++++++++ 开始安装证书 ++++++++
[main] INFO  c.w.w.l.LicenseVerify - [install,48] - 证书安装成功,证书有效期:2025-01-10 00:00:01 - 2025-08-31 09:55:59
[main] INFO  c.w.w.l.c.LicenseCheckListener - [onApplicationEvent,40] - ++++++++ 证书安装结束 ++++++++
  • 启动日志

image-20250822151319693

3、证书API接口

这里提供三个接口,用于证书相关信息的查询:

3.1、服务器信息查询

接口地址:/license/serverInfo METHOD:POST

BODY:storePass的值为发证时提供,与配置的application.yml中的一致,注意安全保管!!!

{
	"storePass":"******"
}

响应数据:

{
    "ipAddress": ["10.168.11.236"],
    "macAddress": ["6C-2F-80-5D-2A-B1"],
    "cpuSerial": "BFEBFBFF000A06A2",
    "mainBoardSerial": "YQ3181249RY00291"
}

3.2、证书有效期限查询

接口地址:/license/info METHOD:POST

BODY:storePass的值为发证时提供,与配置的application.yml中的一致,注意安全保管!!!

{
	"storePass":"******"
}

响应数据:

{
"msg": "证书有效期:2025-01-10 00:00:01 - 2025-08-31 09:55:59",
"code": 200
}

3.3、证书在线更新

证书的更新,只需要向发证方申请,获取新license.lic文件,覆盖原有的文件,即可进行在线接口调用。

接口地址:/license/refresh METHOD:POST

BODY:storePass的值为发证时提供,与配置的application.yml中的一致,注意安全保管!!!

{
	"storePass":"******"
}

响应数据:证书更新成功后,会显示新的截止日期

{
"msg": "证书刷新成功,新证书有效期:2025-01-10 00:00:01 - 2026-12-31 09:55:59",
"code": 200
}

3.4、证书内容获取

证书内容获取非REST API提供,仅提供内部的Server调用,用于在产品中自行来调用获取证书的信息,根据产品业务特点进行自行处理。

// 引入组件
private final LicenseVerify licenseVerify;
// 获取证书内容
licenseVerify.getLicenseContent();

返回数据:包含证书在签发时的所有信息,有效期、IP、MAC地址、业务数据等,在实际的产品使用时自行进行业务层面的应用或验证。

业务数据businesData,该属于用于证书签发时,根据产品业务特征定义的数据,可以是字符,JSON等格式。

consumerAmount: 1 (消费者数量:固定值,不能修改,仅能用于单一登录,不能同一同步多个会话,需业务自行实现)

# 源码验证时,限制了consumerType、consumerAmount的值
de.schlichtherle.license.LicenseManager#validate
  • LicenseContent 对象参考
{
    "holder": {
        "name": "CN=WAF License 2025,OU=DIRI,O=Wiseda,L=BJ,ST=BJ,C=CN",
        "encoded": "MGIxCzAJBgNVBAYTAkNOMQswCQYDVQQIEwJCSjELMAkGA1UEBxMCQkoxDzANBgNVBAoTBldpc2VkYTENMAsGA1UECxMERElSSTEZMBcGA1UEAxMQV0FGIExpY2Vuc2UgMjAyNQ=="
    },
    "issuer": {
        "name": "CN=WAF License 2025,OU=DIRI,O=Wiseda,L=BJ,ST=BJ,C=CN",
        "encoded": "MGIxCzAJBgNVBAYTAkNOMQswCQYDVQQIEwJCSjELMAkGA1UEBxMCQkoxDzANBgNVBAoTBldpc2VkYTENMAsGA1UECxMERElSSTEZMBcGA1UEAxMQV0FGIExpY2Vuc2UgMjAyNQ=="
    },
    "subject": "waf_license",
    "issued": "2025-01-09T16:00:01.000+00:00",
    "notBefore": "2025-01-09T16:00:01.000+00:00",
    "notAfter": "2025-09-11T01:55:59.000+00:00",
    "consumerType": "User",
    "consumerAmount": 1,
    "info": "WAF框架证书",
    "extra": {
        "ipAddress": [
        ],
        "macAddress": [
        ],
        "cpuSerial": "",
        "mainBoardSerial": "",
        "businesData": ""
    }
}

4、证书部署方式

证书部署提供虚拟机环境、docker环境、K8S环境部署方式,同时支持JDK8与JDK17。对于容器化平台的产品部署,没法来固定IP、MAC地址等信息,这里一般只进行证书有效期方式的发证与验证。

4.1、虚拟机环境

# 启动脚本(如需要其他环境变量,自行添加)
java -DSPRING_PROFILE_ACTIVE=dev  \
-DLICENSE_LICENSE_PATH=/opt/waf/license/license.lic  \
-DLICENSE_STORE_PATH=/opt/waf/license/publicCerts.keystore \
-jar waf-framework.jar
  • 外网无法访问

如服务启动只能本机访问,检查一下防火墙端口是否没有开放

#查询已开放端口
firewall-cmd --list-ports
# 开放指定端口(如:8081)
firewall-cmd --zone=public --add-port=8081/tcp --permanent
# 重启防火墙
firewall-cmd --reload

4.2、docker环境

docker环境一般直接将证书文件映射到容器里即可。

# 基于jar文件构建docker镜像
docker build -t waf-framework:1.0 .

# 运行docker镜像
docker run --name waf-server -p 8081:8081 -d   \
-e SPRING_PROFILE_ACTIVE=dev \
-e LICENSE_LICENSE_PATH=/opt/waf/license/license.lic \
-e LICENSE_STORE_PATH=/opt/waf/license/publicCerts.keystore \
-v /opt/waf/license/:/opt/waf/license/  \
waf-framework:1.0
# 删除容器
docker rm -f waf-server
# 删除镜像
docker rmi -f waf-framework:1.0
# 查看容器日志
docker logs -f waf-server

4.3、K8S环境

K8S环境,主要采用以二进制文件的方式将证书写入Configmap中,之后在存储卷中进行挂载到容器中,这样在pod的扩缩容过程中都能正确的加载证书。

4.3.1、镜像构建

  • 将publicCerts.keystore文件复制到resources目录下
  • Dockerfile添加复制publicCerts.keystore脚本,waf-framework模块根据实际项目模块修改
# 复制证书公匙文件
COPY waf-framework/target/classes/publicCerts.keystore /opt/waf/license/publicCerts.keystore
  • Jenkinsfile在docker镜像构建步骤添加复制publicCerts.keystore文件
sourceFiles: 'waf-framework/target/*.jar waf-framework/target/classes/publicCerts.keystore Dockerfile'
  • 文件示例

image-20250825102018244

4.3.2、证书安装

  • 创建二进行文件configmap

将license.lic文件上传到K8S Master节点,需要能执行kubectl命令

# 创建license.lic configmap
kubectl create configmap -n waf license-lic --from-file=./license.lic
# publicCerts.keystore 文件因kubectl 创建时会出现文件读取有异常,这里通过在构建镜像时复制进去
  • 查看configmap

注意: 在华为或阿里云平台,如果没有权限来执行kubectl create的终端,可以先将证书在可以执行kubectl命令的节点上创建(如公司环境或客户堡垒机环境),再到目标节点创建一个普通的configmap后更新yaml,将data改为binaryData,将二进制数据拷贝进来达到同样的效果。

# license.lic示例文件,binaryData节点下为证书的内容
apiVersion: v1
binaryData:
  license.lic: zjFHMSerEEX75Fq+LfS7J5Peuy/8x6AzUWYAnK3/QOJrt8lKLP4BX7vt6kFEbORFvSjO2RhJ0F0BTj7ok3cmduGRbaVWwgpR8KpvXSmGRJ/TltDM7aJVP5MKP5vO2aJuybMMKLdTvQ4WeiETaa9evMhmFWLHfff4HX+L/DRMWRy7KDuwIayKeRtF878unyBzdocImsdcBGwE2TE04TGA01qqsjHFA/VmNQ1EZMo0KquIoSbI16/esXFaXWh2cGeHJziuydZGckkkyh5nejYaj+/vdNeca5/tyZBhRl+mehpsAPUp3k11t+mxeHtMXHO6LQTqvMSrz0ozr+/yG2bp/0C9wGL7sHjswuRXqitiLnbpmkNi2L0N0fe2VhGdhOIuAANezHa5eS7voG+ZqTuljWOECw1rfWEid+R02WIb8bEw87VGOHh7mJPewQKe3iLJDrKJUOtJCp+/XGYgmOsyZBH1+YuKmBJQTqancIhzqhaGaMV2q2xd7vrWHJ+mRtjqs9wEiXy0Ln77tVkIzH1xJfpFZBcK1CREZRN3X50rYwuZccHlVjgYcJ8TXHGIFPXpj+nNYzaoj0FJtlLMisLngjmM7HB4car6InHoigmcSXqWozowKt/++cyVaAXdMOiOd9EAvf3JOfXtFVoQNVfOG/FpjikxM1sLbzn/vQ0t4gkh+Z6OLpj0oEGTaaRyzihZ1dt31EtifLOfjRsWPkJmRdE7OJ8Z8+iKj7msBV9cUUgyWTnxIRDrPhFUkgD6oHeDfAarj52/RIrcRiGRiFz1J4Kk1q2hcRi3ezDoTa+AqjeIgQs0BKKcqwTpyeQ1bGb5voOsr4jH0RuyKLBTGATjWtO9YHXpHYRxoR4PQf2zbljMf0nD31D23iiyXs7X+ymyNrZ/6pxSUPFZ+S2N2YCf9TsIwixxuBXC2sPma3uPX9maW7zZZV02GzeHeA0Pogru4h2Tq/IwjTDLqjx7D1scn72fSDwgA8M388cPVuvPJSQ=
kind: ConfigMap
metadata:
  creationTimestamp: "2025-08-24T08:55:01Z"
  name: license-lic
  namespace: waf
  resourceVersion: "984879225"
  selfLink: /api/v1/namespaces/waf/configmaps/license-lic
  uid: 83c253e7-4469-485e-a5d8-3e8fed6c5021
  • 添加映射卷

卷名:license-vol

默认模式:677

配置映射名:license-lic

容器路径:/opt/waf/license/license.lic (注意与环境变量里配置的一致)

子路径:license.lic

image-20250901171305734

  • 验证启动效果

image-20250825094656240

4.3.3、证书更新

将新签发的证书文件license.lic上传到可执行kubectl的节点进行如下命令替换

# 更新:生成一个包含新license.lic内容的ConfigMap YAML模板,然后通过replace强制替换集群中已存在的同名ConfigMap -n 指标命名空间
kubectl create configmap -n waf license-lic --from-file=./license.lic -o yaml --dry-run=true | kubectl replace -f -

为保证业务不中断,采用滚动更新,先添加新pod,验证证书是否更新正常,确认没问题后,再替换掉旧的pod,达到所有pod按新的证书进行平衡更新替换。

image-20250825094754830

5、证书申请

在客户单位证书过期前一个月需要提醒客户进行新证书申请。

证书过期后,所有后端的业务接口调用都将收到如下响应信息:

  • 接口返回如下信息,表示证书已经过期,需要重新申请授权
{"result":"Your certificate is invalid. Please check if the server has been authorized or apply for a new certificate!"}
  • 申请需要提供的信息如下:
# 申请规范:
申请事由。。。。。
项目编码:
项目名称:
授权的IP:(不限制可不填)
授权的MAC地址:(不限制可不填)
授权的CPU序列号:(不限制可不填)
授权的主板序列号:(不限制可不填)
使用期限:如无限期或指定期限(2025-01-01至2030-12-31)

注意: 该文档涉及的内容均内部配置使用,非客户交流材料!!!

上次更新: 11/1/25, 1:57 PM
编辑者: 李贤伟
Next
waf-calcite-动态数据管理