diff --git a/continew-starter-license/continew-starter-license-generate/README.md b/continew-starter-license/continew-starter-license-generate/README.md
new file mode 100644
index 00000000..c53f6069
--- /dev/null
+++ b/continew-starter-license/continew-starter-license-generate/README.md
@@ -0,0 +1,84 @@
+## continew-starter-license-generate 食用方法
+
+1. 引入依赖
+
+```java
+
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.gnu.org/licenses/lgpl.html + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.license.autoConfiguration; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import top.continew.license.service.LicenseCreateService; + +/** + * @Desc: + * @Author loach + * @ClassName top.continew.license.AutoConfiguration.LicenseGenerateAutoConfiguration + * @Date 2025-03-23 10:57 + */ +@Configuration +public class LicenseGenerateAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public LicenseCreateService licenseCreateService() { + return LicenseCreateService.getInstance(); + } +} diff --git a/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/dto/ConfigParam.java b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/dto/ConfigParam.java new file mode 100644 index 00000000..c6fac16d --- /dev/null +++ b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/dto/ConfigParam.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.gnu.org/licenses/lgpl.html + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.license.dto; + +/** + * @Desc: + * @Author loach + * @ClassName top.continew.license.dto.ConfigParam + * @Date 2025-03-21 14:50 + */ +public class ConfigParam { + + /** 主题 */ + private String subject; + + /** 公钥别称 */ + private String publicAlias; + + /** 访问公钥库的密码 */ + private String storePass; + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getPublicAlias() { + return publicAlias; + } + + public void setPublicAlias(String publicAlias) { + this.publicAlias = publicAlias; + } + + public String getStorePass() { + return storePass; + } + + public void setStorePass(String storePass) { + this.storePass = storePass; + } +} diff --git a/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/dto/LicenseCreatorParam.java b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/dto/LicenseCreatorParam.java new file mode 100644 index 00000000..21c17182 --- /dev/null +++ b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/dto/LicenseCreatorParam.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.gnu.org/licenses/lgpl.html + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.license.dto; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @Desc: + * @Author loach + * @ClassName top.continew.license.dto.LicenseCreatorParam + * @Date 2025-03-21 14:22 + */ +public class LicenseCreatorParam implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** 证书主题 */ + 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"; + + /** + * 用户数量 + */ + private Integer consumerAmount = 1; + + /** 描述信息 */ + private String description; + + /** 额外的服务器硬件校验信息 */ + private LicenseExtraModel licenseExtraModel; + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getPrivateAlias() { + return privateAlias; + } + + public void setPrivateAlias(String privateAlias) { + this.privateAlias = privateAlias; + } + + public String getKeyPass() { + return keyPass; + } + + public void setKeyPass(String keyPass) { + this.keyPass = keyPass; + } + + public String getStorePass() { + return storePass; + } + + public void setStorePass(String storePass) { + this.storePass = storePass; + } + + public String getLicensePath() { + return licensePath; + } + + public void setLicensePath(String licensePath) { + this.licensePath = licensePath; + } + + public String getPrivateKeysStorePath() { + return privateKeysStorePath; + } + + public void setPrivateKeysStorePath(String privateKeysStorePath) { + this.privateKeysStorePath = privateKeysStorePath; + } + + public Date getIssuedTime() { + return issuedTime; + } + + public void setIssuedTime(Date issuedTime) { + this.issuedTime = issuedTime; + } + + public Date getExpiryTime() { + return expiryTime; + } + + public void setExpiryTime(Date expiryTime) { + this.expiryTime = expiryTime; + } + + public String getConsumerType() { + return consumerType; + } + + public void setConsumerType(String consumerType) { + this.consumerType = consumerType; + } + + public Integer getConsumerAmount() { + return consumerAmount; + } + + public void setConsumerAmount(Integer consumerAmount) { + this.consumerAmount = consumerAmount; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public LicenseExtraModel getLicenseExtraModel() { + return licenseExtraModel; + } + + public void setLicenseExtraModel(LicenseExtraModel licenseExtraModel) { + this.licenseExtraModel = licenseExtraModel; + } +} diff --git a/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/dto/LicenseCreatorParamVO.java b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/dto/LicenseCreatorParamVO.java new file mode 100644 index 00000000..137834a8 --- /dev/null +++ b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/dto/LicenseCreatorParamVO.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.gnu.org/licenses/lgpl.html + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.license.dto; + +import java.util.Date; + +/** + * 为用户生成证书需要的具体参数 + * + * @Desc: + * @Author loach + * @ClassName top.continew.license.dto.LicenseCreatorParamVO + * @Date 2025-03-21 14:29 + */ +public class LicenseCreatorParamVO { + + /** + * 有效期截至时间 + */ + private Date expireTime; + + /** + * 客户名称 + */ + private String customerName; + + /** + * 公钥钥库密码库,必须包含数字和字母 + */ + private String storePass; + + /** + * 私钥密码,必须包含数字和字母 + */ + private String keyPass; + + /** + * 描述信息 + */ + private String description; + + /** + * license 保存位置 + */ + private String licenseSavePath; + + public String getLicenseSavePath() { + return licenseSavePath; + } + + public void setLicenseSavePath(String licenseSavePath) { + this.licenseSavePath = licenseSavePath; + } + + /** + * 额外的服务器硬件校验信息 + */ + private LicenseExtraModel licenseExtraModel; + + public Date getExpireTime() { + return expireTime; + } + + public void setExpireTime(Date expireTime) { + this.expireTime = expireTime; + } + + public String getCustomerName() { + return customerName; + } + + public void setCustomerName(String customerName) { + this.customerName = customerName; + } + + public String getStorePass() { + return storePass; + } + + public void setStorePass(String storePass) { + this.storePass = storePass; + } + + public String getKeyPass() { + return keyPass; + } + + public void setKeyPass(String keyPass) { + this.keyPass = keyPass; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public LicenseExtraModel getLicenseExtraModel() { + return licenseExtraModel; + } + + public void setLicenseExtraModel(LicenseExtraModel licenseExtraModel) { + this.licenseExtraModel = licenseExtraModel; + } +} diff --git a/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/dto/LicenseExtraModel.java b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/dto/LicenseExtraModel.java new file mode 100644 index 00000000..63cfcce3 --- /dev/null +++ b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/dto/LicenseExtraModel.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.gnu.org/licenses/lgpl.html + *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.dto;
+
+import java.util.Set;
+
+/**
+ * 额外的服务器硬件校验信息对象,这里的属性可根据需求自定义
+ *
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.dto.LicenseExtraModel
+ * @Date 2025-03-21 14:28
+ */
+public class LicenseExtraModel {
+
+ /**
+ * 可被允许的IP地址
+ */
+ private Set
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.exception;
+
+/**
+ * 自定义证书认证异常
+ *
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.exception.LicenseException
+ * @Date 2025-03-21 14:30
+ */
+public class LicenseException extends RuntimeException {
+
+ public LicenseException(String message) {
+ super(message);
+ }
+}
diff --git a/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/keyStoreParam/CustomKeyStoreParam.java b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/keyStoreParam/CustomKeyStoreParam.java
new file mode 100644
index 00000000..b06325eb
--- /dev/null
+++ b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/keyStoreParam/CustomKeyStoreParam.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.keyStoreParam;
+
+import de.schlichtherle.license.AbstractKeyStoreParam;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.keyStoreParam.CustomKeyStoreParam
+ * @Date 2025-03-21 14:50
+ */
+public class CustomKeyStoreParam extends AbstractKeyStoreParam {
+ /** 密钥路径,可为磁盘路径,也可为项目资源文件里的路径,如果为磁盘路径需重写getStream()方法 */
+ private String storePath;
+
+ /** 公钥或私钥的别名 */
+ private String alias;
+
+ /** 访问公钥/私钥库的密码 */
+ private String storePass;
+
+ /** 公钥/私钥的密码 */
+ private String keyPass;
+
+ public CustomKeyStoreParam(Class clazz, String resource, String alias, String storePass, String keyPass) {
+ super(clazz, resource);
+ this.storePath = resource;
+ this.alias = alias;
+ this.storePass = storePass;
+ this.keyPass = keyPass;
+ }
+
+ @Override
+ public String getAlias() {
+ return alias;
+ }
+
+ @Override
+ public String getStorePwd() {
+ return storePass;
+ }
+
+ @Override
+ public String getKeyPwd() {
+ return keyPass;
+ }
+
+ @Override
+ public InputStream getStream() throws IOException {
+ return new FileInputStream(storePath);
+ }
+}
diff --git a/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/manager/ServerLicenseManager.java b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/manager/ServerLicenseManager.java
new file mode 100644
index 00000000..47ff7e49
--- /dev/null
+++ b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/manager/ServerLicenseManager.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.manager;
+
+import de.schlichtherle.license.*;
+import de.schlichtherle.xml.GenericCertificate;
+
+import java.util.Date;
+
+/**
+ * 自定义服务端证书管理类(生成证书)
+ *
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.manager.ServerLicenseManager
+ * @Date 2025-03-22 14:31
+ */
+public class ServerLicenseManager extends LicenseManager {
+
+ public ServerLicenseManager(LicenseParam param) {
+ super(param);
+ }
+
+ /**
+ * 证书生成参数验证
+ *
+ * @param content
+ * @throws LicenseContentException
+ */
+ protected synchronized void validateCreate(final LicenseContent content) throws LicenseContentException {
+ Date now = new Date();
+ Date notBefore = content.getNotBefore();
+ Date notAfter = content.getNotAfter();
+ if (notBefore != null && now.before(notBefore)) {
+ throw new LicenseContentException("证书尚未生效,无法生成");
+ }
+ if (notAfter != null && now.after(notAfter)) {
+ throw new LicenseContentException("证书已过期,无法生成");
+ }
+
+ if (notBefore != null && notAfter != null && notBefore.after(notAfter)) {
+ throw new LicenseContentException("证书生效时间晚于失效时间,无法生成");
+ }
+ }
+
+ /**
+ * 重写生成证书的方法,增加生成参数验证
+ */
+ @Override
+ protected synchronized byte[] create(LicenseContent content, LicenseNotary notary) throws Exception {
+ initialize(content);
+ validateCreate(content);
+ final GenericCertificate genericCertificate = notary.sign(content);
+ return getPrivacyGuard().cert2key(genericCertificate);
+ }
+}
diff --git a/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/service/LicenseCreateService.java b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/service/LicenseCreateService.java
new file mode 100644
index 00000000..73733ae5
--- /dev/null
+++ b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/service/LicenseCreateService.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.schlichtherle.license.*;
+import net.lingala.zip4j.ZipFile;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import top.continew.license.dto.ConfigParam;
+import top.continew.license.dto.LicenseCreatorParam;
+import top.continew.license.dto.LicenseCreatorParamVO;
+import top.continew.license.dto.LicenseExtraModel;
+import top.continew.license.exception.LicenseException;
+import top.continew.license.keyStoreParam.CustomKeyStoreParam;
+import top.continew.license.manager.ServerLicenseManager;
+import top.continew.license.util.ExecCmdUtil;
+import top.continew.license.util.ServerInfoUtils;
+
+import javax.security.auth.x500.X500Principal;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.*;
+import java.util.prefs.Preferences;
+
+/**
+ * 证书生成接口 实现类
+ *
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.service.impl.LicenseCreateServiceImpl
+ * @Date 2025-03-22 18:36
+ */
+@Component
+public class LicenseCreateService {
+
+ private static final Logger log = LoggerFactory.getLogger(LicenseCreateService.class);
+
+ private static volatile LicenseCreateService instance;
+
+ private LicenseCreateService() {
+ // 私有构造
+ }
+
+ public static LicenseCreateService getInstance() {
+ if (instance == null) {
+ synchronized (LicenseCreateService.class) {
+ if (instance == null) {
+ instance = new LicenseCreateService();
+ }
+ }
+ }
+ return instance;
+ }
+
+ private static final X500Principal DEFAULT_HOLDER_ISSUER = new X500Principal("CN=localhost, OU=localhost, O=localhost, L=SH, ST=SH, C=CN");
+
+ /**
+ * 获取服务器信息
+ *
+ * @return
+ */
+ public LicenseExtraModel getServerInfo() {
+ LicenseExtraModel serverInfos = ServerInfoUtils.getServerInfos();
+ return serverInfos;
+ }
+
+ /**
+ * 生成一个证书
+ *
+ * @param paramVO
+ */
+ public void generateLicense(LicenseCreatorParamVO paramVO) throws Exception {
+
+ Map
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.util;
+
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+
+/**
+ * 运行命令行工具类
+ *
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.util.ExecCmdUtil
+ * @Date 2025-03-22 18:44
+ */
+public class ExecCmdUtil {
+
+ private static final String CREATE_3RDSESSION_SHELL_SCRIPT = "head -n 80 /dev/urandom | tr -dc A-Za-z0-9 | head -c 168";
+
+ /**
+ * 执行cmd命令(shell脚本)
+ *
+ * @param cmd linux sh/windows bat命令
+ * @return String 返回打印信息
+ */
+ public static String exec(String... cmd) throws IOException {
+ Process process = null;
+ if (System.getProperty("os.name").indexOf("Windows") != -1) {
+ if (cmd != null && cmd.length == 1) {
+ process = Runtime.getRuntime().exec(cmd[0]);
+ } else {
+ process = Runtime.getRuntime().exec(cmd);
+ }
+ } else {
+ cmd = ArrayUtils.addAll(new String[] {"/bin/sh", "-c"}, cmd);
+ process = Runtime.getRuntime().exec(cmd);
+ }
+
+ String print = readProcess(process.getInputStream());
+ String err = readProcess(process.getErrorStream());
+ return print + " " + err;
+ }
+
+ private static String readProcess(InputStream in) {
+ try (LineNumberReader print = new LineNumberReader(new InputStreamReader(in, "GBK"))) {
+ StringBuffer sb = new StringBuffer();
+ String line;
+ while ((line = print.readLine()) != null) {
+ sb.append(line);
+ }
+ return sb.toString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+
+ }
+
+ /**
+ * 执行linux命令(shell脚本)生成3rd_session随机数
+ */
+ public static String create3rdSessionToken() throws IOException {
+
+ return exec(CREATE_3RDSESSION_SHELL_SCRIPT);
+ }
+}
diff --git a/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/util/ServerInfoUtils.java b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/util/ServerInfoUtils.java
new file mode 100644
index 00000000..89a85fa6
--- /dev/null
+++ b/continew-starter-license/continew-starter-license-generate/src/main/java/top/continew/license/util/ServerInfoUtils.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.util;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.StrUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import top.continew.license.dto.LicenseExtraModel;
+import top.continew.license.exception.LicenseException;
+
+import java.io.*;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 服务器信息工具类
+ *
+ * @author Rong.Jia
+ * @date 2022/03/10
+ */
+public class ServerInfoUtils {
+
+ private static final Logger log = LoggerFactory.getLogger(ServerInfoUtils.class);
+
+ private static class ServerInfosContainer {
+ private static Set 获取Mac地址 获取IP地址 获取某个网络地址对应的Mac地址 获取当前服务器所有符合条件的网络地址
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.Initializing;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import top.continew.license.bean.LicenseInstallerBean;
+
+/**
+ * 启动校验 License
+ *
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.Initializing.LicenseStarterAutoConfiguration
+ * @Date 2025-04-11 15:40
+ */
+@Configuration
+@EnableConfigurationProperties(LicenseStarterInitializingBean.class)
+public class LicenseStarterInitializingBean implements InitializingBean {
+
+ @Autowired
+ private LicenseInstallerBean licenseInstallerBean;
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+
+ //安装证书,即校验客户机器参数是否符合证书要求,符合则安装成功,不符合则报错无法启动。
+ licenseInstallerBean.installLicense();
+
+ }
+}
diff --git a/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/bean/LicenseInstallerBean.java b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/bean/LicenseInstallerBean.java
new file mode 100644
index 00000000..00c2c550
--- /dev/null
+++ b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/bean/LicenseInstallerBean.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.bean;
+
+import de.schlichtherle.license.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import top.continew.license.config.LicenseVerifyProperties;
+import top.continew.license.exception.VerifyException;
+import top.continew.license.manager.CustomLicenseManager;
+
+import java.io.*;
+
+/**
+ * 证书安装业务类
+ *
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.bean.LicenseInstallerBean
+ * @Date 2025-04-15 15:05
+ */
+public class LicenseInstallerBean {
+
+ private static final Logger log = LoggerFactory.getLogger(LicenseInstallerBean.class);
+
+ private String licensePath;
+
+ private LicenseManager licenseManager;
+
+ private LicenseVerifyProperties properties;
+
+ public LicenseInstallerBean(LicenseVerifyProperties properties) {
+ this.properties = properties;
+
+ if (properties == null || properties.getSavePath() == null) {
+ String os = System.getProperty("os.name");
+ if (os.toLowerCase().contains("windows")) {
+ this.licensePath = "D:/license/";
+ }
+ this.licensePath = "/data/license/";
+ } else {
+ this.licensePath = properties.getSavePath();
+
+ }
+ }
+
+ //安装证书
+ public void installLicense() throws Exception {
+
+ try {
+
+ licenseManager = CustomLicenseManager.getInstance(properties);
+ licenseManager.uninstall();
+ LicenseContent licenseContent = licenseManager
+ .install(new File(getLicensePath() + "clientLicense/license.lic"));
+ log.info("证书认证通过,安装成功");
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new VerifyException("证书认证失败:" + e + " " + e.getMessage());
+ }
+
+ }
+
+ //卸载证书
+ public void uninstallLicense() throws Exception {
+ if (licenseManager != null) {
+ licenseManager.uninstall();
+ //Log.info("证书已卸载");
+ }
+ }
+
+ //即时验证证书合法性
+ public void verify() throws Exception {
+ if (licenseManager != null) {
+ licenseManager.verify();
+ //Log.info("证书认证通过");
+ }
+ throw new VerifyException("证书认证失败:licenseManager is null");
+ }
+
+ /**
+ * 获取license文件位置
+ *
+ * @return
+ */
+ private String getLicensePath() {
+ return licensePath;
+ }
+
+}
diff --git a/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/config/LicenseAutoConfiguration.java b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/config/LicenseAutoConfiguration.java
new file mode 100644
index 00000000..cc15d6af
--- /dev/null
+++ b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/config/LicenseAutoConfiguration.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.config;
+
+import de.schlichtherle.license.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import top.continew.license.bean.LicenseInstallerBean;
+import top.continew.license.manager.CustomLicenseManager;
+
+/**
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.config.LicenseAutoConfiguration
+ * @Date 2025-04-15 15:17
+ */
+@Configuration
+public class LicenseAutoConfiguration {
+
+ private String licensePath;
+
+ @Bean
+ public LicenseVerifyProperties licenseVerifyProperties() {
+ return new LicenseVerifyProperties();
+ }
+
+ @Bean
+ public LicenseInstallerBean licenseInstallerBean(LicenseVerifyProperties properties) {
+ return new LicenseInstallerBean(properties);
+ }
+
+ @Bean
+ public LicenseManager licenseManager(LicenseVerifyProperties properties) {
+ return CustomLicenseManager.getInstance(properties);
+ }
+
+}
diff --git a/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/config/LicenseVerifyProperties.java b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/config/LicenseVerifyProperties.java
new file mode 100644
index 00000000..4078fa53
--- /dev/null
+++ b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/config/LicenseVerifyProperties.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.config.LicenseYmlConfig
+ * @Date 2025-04-14 14:56
+ */
+@ConfigurationProperties(prefix = "license")
+public class LicenseVerifyProperties {
+
+ private String savePath;
+
+ public String getSavePath() {
+ return savePath;
+ }
+
+ public void setSavePath(String savePath) {
+ this.savePath = savePath;
+ }
+
+}
diff --git a/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/dto/ConfigParam.java b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/dto/ConfigParam.java
new file mode 100644
index 00000000..9f9d3331
--- /dev/null
+++ b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/dto/ConfigParam.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.dto;
+
+/**
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.dto.ConfigParam
+ * @Date 2025-03-21 14:50
+ */
+public class ConfigParam {
+
+ /**
+ * 主题
+ */
+ private String subject;
+
+ /**
+ * 公钥别称
+ */
+ private String publicAlias;
+
+ /**
+ * 访问公钥库的密码
+ */
+ private String storePass;
+
+ public String getSubject() {
+ return subject;
+ }
+
+ public void setSubject(String subject) {
+ this.subject = subject;
+ }
+
+ public String getPublicAlias() {
+ return publicAlias;
+ }
+
+ public void setPublicAlias(String publicAlias) {
+ this.publicAlias = publicAlias;
+ }
+
+ public String getStorePass() {
+ return storePass;
+ }
+
+ public void setStorePass(String storePass) {
+ this.storePass = storePass;
+ }
+}
diff --git a/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/dto/LicenseExtraModel.java b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/dto/LicenseExtraModel.java
new file mode 100644
index 00000000..63cfcce3
--- /dev/null
+++ b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/dto/LicenseExtraModel.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.dto;
+
+import java.util.Set;
+
+/**
+ * 额外的服务器硬件校验信息对象,这里的属性可根据需求自定义
+ *
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.dto.LicenseExtraModel
+ * @Date 2025-03-21 14:28
+ */
+public class LicenseExtraModel {
+
+ /**
+ * 可被允许的IP地址
+ */
+ private Set
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.exception;
+
+/**
+ * 自定义校验异常
+ *
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.exception.VerifyException
+ * @Date 2025-04-11 14:58
+ */
+public class VerifyException extends RuntimeException {
+ public VerifyException(String message) {
+ super(message);
+ }
+
+}
diff --git a/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/keyStoreParam/CustomKeyStoreParam.java b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/keyStoreParam/CustomKeyStoreParam.java
new file mode 100644
index 00000000..f91a5e8e
--- /dev/null
+++ b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/keyStoreParam/CustomKeyStoreParam.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.keyStoreParam;
+
+import de.schlichtherle.license.AbstractKeyStoreParam;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.keyStoreParam.CustomKeyStoreParam
+ * @Date 2025-04-12 14:50
+ */
+public class CustomKeyStoreParam extends AbstractKeyStoreParam {
+ /** 密钥路径,可为磁盘路径,也可为项目资源文件里的路径,如果为磁盘路径需重写getStream()方法 */
+ private String storePath;
+
+ /** 公钥或私钥的别名 */
+ private String alias;
+
+ /** 访问公钥/私钥库的密码 */
+ private String storePass;
+
+ /** 公钥/私钥的密码 */
+ private String keyPass;
+
+ public CustomKeyStoreParam(Class clazz, String resource, String alias, String storePass, String keyPass) {
+ super(clazz, resource);
+ this.storePath = resource;
+ this.alias = alias;
+ this.storePass = storePass;
+ this.keyPass = keyPass;
+ }
+
+ @Override
+ public String getAlias() {
+ return alias;
+ }
+
+ @Override
+ public String getStorePwd() {
+ return storePass;
+ }
+
+ @Override
+ public String getKeyPwd() {
+ return keyPass;
+ }
+
+ @Override
+ public InputStream getStream() throws IOException {
+ return new FileInputStream(storePath);
+ }
+}
diff --git a/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/manager/CustomLicenseManager.java b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/manager/CustomLicenseManager.java
new file mode 100644
index 00000000..223f6cf6
--- /dev/null
+++ b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/manager/CustomLicenseManager.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.manager;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.schlichtherle.license.*;
+import de.schlichtherle.xml.GenericCertificate;
+import net.lingala.zip4j.ZipFile;
+import net.lingala.zip4j.exception.ZipException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import top.continew.license.bean.LicenseInstallerBean;
+import top.continew.license.config.LicenseVerifyProperties;
+import top.continew.license.dto.ConfigParam;
+import top.continew.license.dto.LicenseExtraModel;
+import top.continew.license.keyStoreParam.CustomKeyStoreParam;
+import top.continew.license.utils.ServerInfoUtils;
+
+import java.io.*;
+import java.util.prefs.Preferences;
+
+/**
+ * 客户端证书管理类(证书验证)
+ *
+ * @Desc:
+ * @Author loach
+ * @ClassName top.continew.license.manager.ClientLicenseManager
+ * @Date 2025-04-11 15:00
+ */
+@Component
+public class CustomLicenseManager extends LicenseManager {
+
+ private static final Logger log = LoggerFactory.getLogger(CustomLicenseManager.class);
+
+ private static volatile CustomLicenseManager INSTANCE;
+ private LicenseExtraModel extraModel;
+
+ public static CustomLicenseManager getInstance(LicenseVerifyProperties properties) {
+ if (INSTANCE == null) {
+ synchronized (CustomLicenseManager.class) {
+ if (INSTANCE == null) {
+ INSTANCE = new CustomLicenseManager(properties);
+ }
+ }
+ }
+ return INSTANCE;
+ }
+
+ private String licensePath;
+
+ public CustomLicenseManager(LicenseVerifyProperties properties) {
+ if (properties == null || properties.getSavePath() == null) {
+ String os = System.getProperty("os.name");
+ if (os.toLowerCase().contains("windows")) {
+ this.licensePath = "D:/license/";
+ }
+ this.licensePath = "/data/license/";
+ } else {
+ this.licensePath = properties.getSavePath();
+
+ }
+ //初始化服务信息
+ initServerExtraModel();
+ //解压证书和配置文件等
+ extractZip();
+ //获取配置文件
+ ConfigParam configParam = getConfigParam();
+ //安装证书
+ Preferences preferences = Preferences.userNodeForPackage(LicenseInstallerBean.class);
+ CipherParam cipherParam = new DefaultCipherParam(configParam.getStorePass());
+ KeyStoreParam publicKeyStoreParam = new CustomKeyStoreParam(LicenseInstallerBean.class, getLicensePath() + "clientLicense/publicCerts.keystore", configParam
+ .getPublicAlias(), configParam.getStorePass(), null);
+ LicenseParam licenseParam = new DefaultLicenseParam(configParam
+ .getSubject(), preferences, publicKeyStoreParam, cipherParam);
+
+ super.setLicenseParam(licenseParam);
+ }
+
+ private void initServerExtraModel() {
+ this.extraModel = ServerInfoUtils.getServerInfos();
+ }
+
+ /**
+ * 解压压缩包
+ *
+ * @throws ZipException
+ */
+ private void extractZip() {
+ ZipFile config = new ZipFile(getLicensePath() + "clientLicense.zip");
+ File licenseDir = new File(getLicensePath() + "clientLicense");
+ if (!licenseDir.exists()) {
+ licenseDir.mkdir();
+ }
+ try {
+ config.extractAll(licenseDir.getAbsolutePath());
+ } catch (ZipException e) {
+ log.error(e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * 获取压缩文件中配置的基础参数
+ *
+ * @return
+ * @throws Exception
+ */
+ private ConfigParam getConfigParam() {
+ FileInputStream config = null;
+ BufferedReader reader = null;
+ try {
+ config = new FileInputStream(getLicensePath() + "clientLicense/clientConfig.json");
+ reader = new BufferedReader(new InputStreamReader(config, "UTF-8"));
+ StringBuilder sb = new StringBuilder();
+ String temp = null;
+ while ((temp = reader.readLine()) != null) {
+ sb.append(temp);
+ }
+ ObjectMapper mapper = new ObjectMapper();
+ ConfigParam configParam = mapper.readValue(sb.toString(), ConfigParam.class);
+ return configParam;
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ if (config != null) {
+ try {
+ config.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 获取license文件位置
+ *
+ * @return
+ */
+ private String getLicensePath() {
+ return this.licensePath;
+ }
+
+ /**
+ * 重写验证证书方法,添加自定义参数验证
+ */
+ @Override
+ protected synchronized void validate(LicenseContent content) throws LicenseContentException {
+ //系统验证基本参数:生效时间、失效时间、公钥别名、公钥密码
+ super.validate(content);
+ //验证自定义参数
+ Object o = content.getExtra();
+ if (o != null && extraModel != null && o instanceof LicenseExtraModel) {
+ LicenseExtraModel contentExtraModel = (LicenseExtraModel)o;
+ if (!contentExtraModel.getCpuSerial().equals(extraModel.getCpuSerial())) {
+ throw new LicenseContentException("CPU核数不匹配");
+ }
+ if (!contentExtraModel.getMainBoardSerial().equals(extraModel.getMainBoardSerial())) {
+ throw new LicenseContentException("主板序列号不匹配");
+ }
+ if (!contentExtraModel.getIpAddress().equals(extraModel.getIpAddress())) {
+ throw new LicenseContentException("IP地址不匹配");
+ }
+ if (!contentExtraModel.getMacAddress().equals(extraModel.getMacAddress())) {
+ throw new LicenseContentException("MAC地址不匹配");
+ }
+ } else {
+ throw new LicenseContentException("证书无效");
+ }
+ }
+
+ /**
+ * 重写证书安装方法,主要是更改调用本类的验证方法
+ */
+ @Override
+ protected synchronized LicenseContent install(final byte[] key, LicenseNotary notary) throws Exception {
+
+ final GenericCertificate certificate = getPrivacyGuard().key2cert(key);
+ notary.verify(certificate);
+ final LicenseContent content = (LicenseContent)certificate.getContent();
+ this.validate(content);
+ setLicenseKey(key);
+ setCertificate(certificate);
+
+ return content;
+ }
+
+ /**
+ * 重写验证证书合法的方法,主要是更改调用本类的验证方法
+ */
+ @Override
+ protected synchronized LicenseContent verify(LicenseNotary notary) throws Exception {
+ GenericCertificate certificate = getCertificate();
+ if (null != certificate)
+ return (LicenseContent)certificate.getContent();
+
+ // Load license key from preferences,
+ final byte[] key = getLicenseKey();
+ if (null == key)
+ throw new NoLicenseInstalledException(getLicenseParam().getSubject());
+ certificate = getPrivacyGuard().key2cert(key);
+ notary.verify(certificate);
+ final LicenseContent content = (LicenseContent)certificate.getContent();
+ this.validate(content);
+ setCertificate(certificate);
+
+ return content;
+ }
+}
diff --git a/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/utils/ServerInfoUtils.java b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/utils/ServerInfoUtils.java
new file mode 100644
index 00000000..7d499fe4
--- /dev/null
+++ b/continew-starter-license/continew-starter-license-verify/src/main/java/top/continew/license/utils/ServerInfoUtils.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.license.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.StrUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import top.continew.license.dto.LicenseExtraModel;
+import top.continew.license.exception.VerifyException;
+
+import java.io.*;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 服务器信息工具类
+ *
+ * @author Rong.Jia
+ * @date 2022/03/10
+ */
+public class ServerInfoUtils {
+
+ private static final Logger log = LoggerFactory.getLogger(ServerInfoUtils.class);
+
+ private static class ServerInfosContainer {
+ private static Set 获取Mac地址 获取IP地址 获取某个网络地址对应的Mac地址 获取当前服务器所有符合条件的网络地址