From 3882d5d980d8889599f35c4eb2b88ce3e26428ec Mon Sep 17 00:00:00 2001 From: liyongde <1419499670@qq.com> Date: Wed, 27 Aug 2025 10:50:28 +0800 Subject: [PATCH] =?UTF-8?q?opt:=20=E7=BB=93=E6=9E=84=E5=8F=98=E5=8C=96?= =?UTF-8?q?=EF=BC=8C=E6=B5=8B=E8=AF=95=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nl-verify-check-sdk/pom.xml | 7 +-- .../java/org/nl/core/AuthInterceptor.java | 54 +++++++------------ .../org/nl/core/LicenseAutoConfiguration.java | 47 ++++++++++++++++ .../java/org/nl/core/LicenseProperties.java | 32 +++++++++++ .../java/org/nl/core/LicenseVerifier.java | 37 +++++++++++++ .../src/main/java/org/nl/core/WebConfig.java | 17 ------ .../src/main/java/org/nl/util/RSAUtil.java | 50 +++++++++++------ .../main/resources/META-INF/spring.factories | 4 ++ .../main/java/org/nl/GenerateAuthCode.java | 4 +- .../src/main/resources/application.yml | 3 ++ .../src/main/resources/private_key.txt | 0 11 files changed, 178 insertions(+), 77 deletions(-) create mode 100644 nl-verify-check-sdk/src/main/java/org/nl/core/LicenseAutoConfiguration.java create mode 100644 nl-verify-check-sdk/src/main/java/org/nl/core/LicenseProperties.java create mode 100644 nl-verify-check-sdk/src/main/java/org/nl/core/LicenseVerifier.java delete mode 100644 nl-verify-check-sdk/src/main/java/org/nl/core/WebConfig.java create mode 100644 nl-verify-check-sdk/src/main/resources/META-INF/spring.factories create mode 100644 nl-verify-check-test/src/main/resources/application.yml rename {nl-verify-check-sdk => nl-verify-check-test}/src/main/resources/private_key.txt (100%) diff --git a/nl-verify-check-sdk/pom.xml b/nl-verify-check-sdk/pom.xml index 91d3fa3..3f0b88a 100644 --- a/nl-verify-check-sdk/pom.xml +++ b/nl-verify-check-sdk/pom.xml @@ -21,7 +21,7 @@ org.springframework.boot spring-boot-starter-web - 2.7.3 + 2.6.4 org.projectlombok @@ -29,11 +29,6 @@ 1.18.22 compile - - com.alibaba - fastjson - 1.2.83 - diff --git a/nl-verify-check-sdk/src/main/java/org/nl/core/AuthInterceptor.java b/nl-verify-check-sdk/src/main/java/org/nl/core/AuthInterceptor.java index c6a0d64..ac694d9 100644 --- a/nl-verify-check-sdk/src/main/java/org/nl/core/AuthInterceptor.java +++ b/nl-verify-check-sdk/src/main/java/org/nl/core/AuthInterceptor.java @@ -1,51 +1,35 @@ package org.nl.core; -import com.alibaba.fastjson.JSONObject; -import org.nl.util.RSAUtil; -import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; /** * @Author: lyd * @Date: 2025/8/26 */ -public class AuthInterceptor extends HandlerInterceptorAdapter { +public class AuthInterceptor implements HandlerInterceptor { + private final LicenseProperties properties; + private final LicenseVerifier verifier; + private final ObjectMapper objectMapper = new ObjectMapper(); + public AuthInterceptor(LicenseProperties properties, LicenseVerifier verifier) { + this.properties = properties; + this.verifier = verifier; + } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - String authCode = request.getHeader("cdk"); // 假设从 Header 获取 - - if (authCode == null || authCode.isEmpty()) { - response.setContentType("text/html;charset=UTF-8"); - response.setStatus(402); - response.getWriter().write(JSONObject.toJSONString(LicenseResult.requestResult(false, "请收入授权码", null))); - return false; + String headerName = properties.getHeader(); + String authCode = request.getHeader(headerName); + LicenseResult result = verifier.verify(authCode); + if (Boolean.TRUE.equals(result.getResult())) { + return true; } - String expirationStr =""; - try { - // 解密获取到期时间 - expirationStr = RSAUtil.decrypt(authCode); - if ("-1".equals(expirationStr)) { - return true; - } - LocalDate expirationDate = LocalDate.parse(expirationStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); - if (LocalDate.now().isAfter(expirationDate)) { - response.setContentType("text/html;charset=UTF-8"); - response.setStatus(402); - response.getWriter().write(JSONObject.toJSONString(LicenseResult.requestResult(false, "授权码已到期", null))); - return false; - } - } catch (Exception e) { - // 解密失败或格式错误 - response.setContentType("text/html;charset=UTF-8"); - response.setStatus(402); - response.getWriter().write(JSONObject.toJSONString(LicenseResult.requestResult(false, "解密失败或格式错误", null))); - return false; - } - return true; + response.setContentType("application/json;charset=UTF-8"); + response.setStatus(402); + response.getWriter().write(objectMapper.writeValueAsString(result)); + return false; } } diff --git a/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseAutoConfiguration.java b/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseAutoConfiguration.java new file mode 100644 index 0000000..ef867a4 --- /dev/null +++ b/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseAutoConfiguration.java @@ -0,0 +1,47 @@ +package org.nl.core; + +import org.nl.util.RSAUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +@EnableConfigurationProperties(LicenseProperties.class) +@ConditionalOnClass(WebMvcConfigurer.class) +public class LicenseAutoConfiguration implements WebMvcConfigurer { + + @Autowired + @Lazy + private AuthInterceptor authInterceptor; + + @Bean + @ConditionalOnMissingBean + public RSAUtil rsaUtil(LicenseProperties properties) { + return new RSAUtil(properties.getPrivateKeyLocation()); + } + + @Bean + @ConditionalOnMissingBean + public LicenseVerifier licenseVerifier(RSAUtil rsaUtil) { + return new LicenseVerifier(rsaUtil); + } + + @Bean + @ConditionalOnMissingBean + public AuthInterceptor authInterceptor(LicenseProperties properties, LicenseVerifier verifier) { + return new AuthInterceptor(properties, verifier); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(authInterceptor).addPathPatterns("/**"); + } +} + + diff --git a/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseProperties.java b/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseProperties.java new file mode 100644 index 0000000..e3dd872 --- /dev/null +++ b/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseProperties.java @@ -0,0 +1,32 @@ +package org.nl.core; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 授权校验可配置属性 + * @Author: lyd + * @Date: 2025/8/27 + */ +@ConfigurationProperties(prefix = "nl.license") +public class LicenseProperties { + /** header 名称,默认 cdk */ + private String header = "cdk"; + /** 私钥资源位置,默认 classpath:private_key.txt */ + private String privateKeyLocation = "classpath:private_key.txt"; + + public String getHeader() { + return header; + } + + public void setHeader(String header) { + this.header = header; + } + + public String getPrivateKeyLocation() { + return privateKeyLocation; + } + + public void setPrivateKeyLocation(String privateKeyLocation) { + this.privateKeyLocation = privateKeyLocation; + } +} diff --git a/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseVerifier.java b/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseVerifier.java new file mode 100644 index 0000000..8085f05 --- /dev/null +++ b/nl-verify-check-sdk/src/main/java/org/nl/core/LicenseVerifier.java @@ -0,0 +1,37 @@ +package org.nl.core; + +import org.nl.util.RSAUtil; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +/** + * @Author: lyd + * @Date: 2025/8/27 + */ +public class LicenseVerifier { + private final RSAUtil rsaUtil; + + public LicenseVerifier(RSAUtil rsaUtil) { + this.rsaUtil = rsaUtil; + } + + public LicenseResult verify(String authCode) { + if (authCode == null || authCode.isEmpty()) { + return LicenseResult.requestResult(false, "请输入授权码", null); + } + try { + String expirationStr = rsaUtil.decrypt(authCode); + if ("-1".equals(expirationStr)) { + return LicenseResult.requestOk("永久授权", expirationStr); + } + LocalDate expirationDate = LocalDate.parse(expirationStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + if (LocalDate.now().isAfter(expirationDate)) { + return LicenseResult.requestResult(false, "授权码已到期", expirationStr); + } + return LicenseResult.requestOk("授权码有效", expirationStr); + } catch (Exception e) { + return LicenseResult.requestResult(false, "解密失败或格式错误", null); + } + } +} diff --git a/nl-verify-check-sdk/src/main/java/org/nl/core/WebConfig.java b/nl-verify-check-sdk/src/main/java/org/nl/core/WebConfig.java deleted file mode 100644 index da45213..0000000 --- a/nl-verify-check-sdk/src/main/java/org/nl/core/WebConfig.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.nl.core; - -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -/** - * @Author: lyd - * @Date: 2025/8/26 - */ -@Configuration -public class WebConfig implements WebMvcConfigurer { - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(new AuthInterceptor()).addPathPatterns("/**"); - } -} diff --git a/nl-verify-check-sdk/src/main/java/org/nl/util/RSAUtil.java b/nl-verify-check-sdk/src/main/java/org/nl/util/RSAUtil.java index e67f8a8..d191a66 100644 --- a/nl-verify-check-sdk/src/main/java/org/nl/util/RSAUtil.java +++ b/nl-verify-check-sdk/src/main/java/org/nl/util/RSAUtil.java @@ -1,10 +1,16 @@ package org.nl.util; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; import org.springframework.util.ResourceUtils; import javax.crypto.Cipher; import java.io.BufferedReader; import java.io.FileReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.PKCS8EncodedKeySpec; @@ -15,31 +21,41 @@ import java.util.Base64; * @Date: 2025/8/13 */ public class RSAUtil { - private static PrivateKey privateKey; - public static synchronized PrivateKey getPrivateKey() throws Exception { + private final String privateKeyLocation; + + private PrivateKey privateKey; + + private final ResourceLoader resourceLoader = new DefaultResourceLoader(); + + public RSAUtil(String privateKeyLocation) { + this.privateKeyLocation = privateKeyLocation; + } + + + public synchronized PrivateKey getPrivateKey() throws Exception { if (privateKey == null) { - // 从 resources/private_key.txt 读取 Base64 - String filePath = ResourceUtils.getFile("classpath:private_key.txt").getPath(); - BufferedReader reader = new BufferedReader(new FileReader(filePath)); - StringBuilder sb = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - sb.append(line); + Resource resource = resourceLoader.getResource(privateKeyLocation); + try (InputStream is = resource.getInputStream(); + InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8); + BufferedReader reader = new BufferedReader(isr)) { + StringBuilder sb = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + sb.append(line.trim()); + } + byte[] privateKeyBytes = Base64.getDecoder().decode(sb.toString()); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + privateKey = keyFactory.generatePrivate(keySpec); } - reader.close(); - - byte[] privateKeyBytes = Base64.getDecoder().decode(sb.toString()); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - privateKey = keyFactory.generatePrivate(keySpec); } return privateKey; } - public static String decrypt(String authCode) throws Exception { + public String decrypt(String authCode) throws Exception { byte[] encryptedBytes = Base64.getDecoder().decode(authCode); - Cipher cipher = Cipher.getInstance("RSA"); + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, getPrivateKey()); byte[] decrypted = cipher.doFinal(encryptedBytes); return new String(decrypted, "UTF-8"); diff --git a/nl-verify-check-sdk/src/main/resources/META-INF/spring.factories b/nl-verify-check-sdk/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..477120b --- /dev/null +++ b/nl-verify-check-sdk/src/main/resources/META-INF/spring.factories @@ -0,0 +1,4 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.nl.core.LicenseAutoConfiguration + + diff --git a/nl-verify-check-test/src/main/java/org/nl/GenerateAuthCode.java b/nl-verify-check-test/src/main/java/org/nl/GenerateAuthCode.java index 4679068..2dc0d35 100644 --- a/nl-verify-check-test/src/main/java/org/nl/GenerateAuthCode.java +++ b/nl-verify-check-test/src/main/java/org/nl/GenerateAuthCode.java @@ -22,8 +22,8 @@ public class GenerateAuthCode { PublicKey publicKey = keyFactory.generatePublic(keySpec); // 加密 -// Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // 标准填充模式 - Cipher cipher = Cipher.getInstance("RSA"); // 标准填充模式 + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // 标准填充模式 +// Cipher cipher = Cipher.getInstance("RSA"); // 标准填充模式 cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] encrypted = cipher.doFinal(expirationDate.getBytes("UTF-8")); String authCode = Base64.getEncoder().encodeToString(encrypted); diff --git a/nl-verify-check-test/src/main/resources/application.yml b/nl-verify-check-test/src/main/resources/application.yml new file mode 100644 index 0000000..c662588 --- /dev/null +++ b/nl-verify-check-test/src/main/resources/application.yml @@ -0,0 +1,3 @@ +nl: + license: + header: "cdk" diff --git a/nl-verify-check-sdk/src/main/resources/private_key.txt b/nl-verify-check-test/src/main/resources/private_key.txt similarity index 100% rename from nl-verify-check-sdk/src/main/resources/private_key.txt rename to nl-verify-check-test/src/main/resources/private_key.txt