From 9349240e384956c73d2b7ea792d8d5133eeee2e8 Mon Sep 17 00:00:00 2001 From: Hamm Date: Tue, 4 Jun 2024 20:03:35 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(BUG):=20=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E5=B7=B2=E7=9F=A5=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interceptor/AbstractRequestInterceptor.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/airpower-core/src/main/java/cn/hamm/airpower/interceptor/AbstractRequestInterceptor.java b/airpower-core/src/main/java/cn/hamm/airpower/interceptor/AbstractRequestInterceptor.java index 13082a4..9f750cd 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/interceptor/AbstractRequestInterceptor.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/interceptor/AbstractRequestInterceptor.java @@ -74,7 +74,10 @@ public abstract class AbstractRequestInterceptor implements HandlerInterceptor { } } - beforeHandleRequest(request, response, clazz, method); + boolean isContinue = beforeHandleRequest(request, response, clazz, method); + if (!isContinue) { + return true; + } Access access = Utils.getAccessUtil().getWhatNeedAccess(clazz, method); if (!access.isLogin()) { // 不需要登录 直接返回有权限 @@ -118,11 +121,14 @@ public abstract class AbstractRequestInterceptor implements HandlerInterceptor { * @param response 响应对象 * @param clazz 控制器类 * @param method 执行方法 + * @return 拦截结果 + * @apiNote 如返回TRUE,则继续走后续拦截,如返回FALSE,则中断拦截,直接放行 */ @SuppressWarnings({"EmptyMethod", "unused"}) - protected void beforeHandleRequest( + protected boolean beforeHandleRequest( HttpServletRequest request, HttpServletResponse response, Class clazz, Method method ) { + return true; } /** -- Gitee From 3cda61a03e1725ac14e3a3dd5b375d95e8254545 Mon Sep 17 00:00:00 2001 From: Hamm Date: Wed, 5 Jun 2024 20:55:47 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(BUG):=20=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E5=B7=B2=E7=9F=A5=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/hamm/airpower/util/AesUtil.java | 181 ++++++++++++++++++ .../cn/hamm/airpower/util/DictionaryUtil.java | 8 +- .../java/cn/hamm/airpower/util/EmailUtil.java | 3 + .../cn/hamm/airpower/util/RandomUtil.java | 43 +++-- .../java/cn/hamm/airpower/util/RsaUtil.java | 82 ++++++-- .../java/cn/hamm/airpower/util/Utils.java | 10 +- 6 files changed, 297 insertions(+), 30 deletions(-) create mode 100644 airpower-core/src/main/java/cn/hamm/airpower/util/AesUtil.java diff --git a/airpower-core/src/main/java/cn/hamm/airpower/util/AesUtil.java b/airpower-core/src/main/java/cn/hamm/airpower/util/AesUtil.java new file mode 100644 index 0000000..63e0ba5 --- /dev/null +++ b/airpower-core/src/main/java/cn/hamm/airpower/util/AesUtil.java @@ -0,0 +1,181 @@ +package cn.hamm.airpower.util; + + +import cn.hamm.airpower.exception.ServiceException; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.springframework.stereotype.Component; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Base64; + +/** + *

AES助手

+ * + * @author Hamm.cn + */ +@Component +public class AesUtil { + private static final int KEY_SIZE = 256; + + private static final String AES = "AES"; + + /** + *

AES/CBC/PKCS5Padding

+ */ + private static final String AES_CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding"; + + /** + *

密钥

+ */ + private byte[] key; + + /** + *

偏移向量

+ */ + private byte[] iv = "0000000000000000".getBytes(StandardCharsets.UTF_8); + + /** + *

设置偏移向量

+ * + * @param iv 偏移向量 + * @return AesUtil + */ + public AesUtil setIv(String iv) { + this.iv = Base64.getDecoder().decode(iv); + return this; + } + + /** + *

算法

+ */ + private String algorithm = AES_CBC_PKCS5_PADDING; + + /** + *

设置算法

+ * + * @param algorithm 算法 + * @return AesUtil + */ + public AesUtil setAlgorithm(String algorithm) { + this.algorithm = algorithm; + return this; + } + + /** + *

设置密钥

+ * + * @param key 密钥 + * @return AesUtil + */ + public AesUtil setKey(String key) { + this.key = Base64.getDecoder().decode(key); + return this; + } + + /** + *

加密

+ * + * @param source 待加密的内容 + * @return 加密后的内容 + */ + public final String encrypt(String source) { + try { + return Base64.getEncoder().encodeToString(getCipher(Cipher.ENCRYPT_MODE).doFinal(source.getBytes(StandardCharsets.UTF_8))); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + *

解密

+ * + * @param content 加密后的内容 + * @return 解密后的内容 + */ + @Contract("_ -> new") + public final @NotNull String decrypt(String content) { + try { + return new String(getCipher(Cipher.DECRYPT_MODE).doFinal(Base64.getDecoder().decode(content)), StandardCharsets.UTF_8); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + *

获取Cipher

+ * + * @param mode 模式 + * @return Cipher + */ + private @NotNull Cipher getCipher(int mode) { + System.out.println(key.length); + System.out.println(new String(key)); + System.out.println(iv.length); + System.out.println(new String(iv)); + try { + SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); + + Cipher cipher = Cipher.getInstance(algorithm); + cipher.init(mode, secretKeySpec, ivParameterSpec); + return cipher; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + String keyStr = AesUtil.getRandomKey(); + System.out.println(keyStr); + String message = "Hello, this is a secret message!"; + String encrypted = new AesUtil().setKey(keyStr).encrypt(message); + System.out.println("Encoded Encrypted Text: " + encrypted); + + String decrypted = new AesUtil().setKey(keyStr).decrypt(encrypted); + System.out.println("Decrypted Text: " + decrypted); + } + + /** + *

获取随机密钥

+ * + * @return 随机密钥 + */ + @Contract(" -> new") + public static @NotNull String getRandomKey() { + try { + KeyGenerator keyGen = KeyGenerator.getInstance(AES); + keyGen.init(KEY_SIZE, new SecureRandom()); + SecretKey aesKey = keyGen.generateKey(); + byte[] keyBytes = aesKey.getEncoded(); + return Base64.getEncoder().encodeToString(keyBytes); + } catch (NoSuchAlgorithmException e) { + throw new ServiceException(e); + } + } + + /** + *

获取随机密钥

+ * + * @return 随机密钥 + */ + @Contract(" -> new") + public static @NotNull String getRandomIv() { + try { + KeyGenerator keyGen = KeyGenerator.getInstance(AES); + keyGen.init(KEY_SIZE / 2, new SecureRandom()); + SecretKey aesKey = keyGen.generateKey(); + byte[] keyBytes = aesKey.getEncoded(); + return Base64.getEncoder().encodeToString(keyBytes); + } catch (NoSuchAlgorithmException e) { + throw new ServiceException(e); + } + } +} diff --git a/airpower-core/src/main/java/cn/hamm/airpower/util/DictionaryUtil.java b/airpower-core/src/main/java/cn/hamm/airpower/util/DictionaryUtil.java index 6a5a218..0eb1e7c 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/util/DictionaryUtil.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/util/DictionaryUtil.java @@ -1,10 +1,10 @@ package cn.hamm.airpower.util; +import cn.hamm.airpower.exception.ServiceException; import cn.hamm.airpower.interfaces.IDictionary; import cn.hamm.airpower.interfaces.IFunction; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; @@ -31,7 +31,7 @@ public class DictionaryUtil { * @param [泛型] 字典类型 * @return 查到的字典 */ - public final @Nullable D getDictionary(@NotNull Class enumClass, int key) { + public final @NotNull D getDictionary(@NotNull Class enumClass, int key) { return getDictionary(enumClass, IDictionary::getKey, key); } @@ -44,7 +44,7 @@ public class DictionaryUtil { * @param [泛型] 字典类型 * @return 查到的字典 */ - public final @Nullable D getDictionary(@NotNull Class enumClass, Function function, Object value) { + public final @NotNull D getDictionary(@NotNull Class enumClass, Function function, Object value) { try { // 取出所有枚举类型 D[] objs = enumClass.getEnumConstants(); @@ -56,7 +56,7 @@ public class DictionaryUtil { } catch (Exception exception) { log.error(exception.getMessage(), exception); } - return null; + throw new ServiceException("传入的值不在字典可选范围内"); } /** diff --git a/airpower-core/src/main/java/cn/hamm/airpower/util/EmailUtil.java b/airpower-core/src/main/java/cn/hamm/airpower/util/EmailUtil.java index 1051719..7b6cbd8 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/util/EmailUtil.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/util/EmailUtil.java @@ -21,6 +21,9 @@ public class EmailUtil { @Autowired(required = false) private JavaMailSender javaMailSender; + /** + *

发件人/用户名

+ */ @Value("${spring.mail.username: ''}") private String mailFrom; diff --git a/airpower-core/src/main/java/cn/hamm/airpower/util/RandomUtil.java b/airpower-core/src/main/java/cn/hamm/airpower/util/RandomUtil.java index 14a8f14..65a6881 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/util/RandomUtil.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/util/RandomUtil.java @@ -7,6 +7,8 @@ import org.springframework.util.StringUtils; import java.util.Random; import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; +import java.util.stream.IntStream; /** *

随机助手类

@@ -35,6 +37,26 @@ public class RandomUtil { */ private static final String BASE_CHAR_NUMBER = BASE_CHAR.toUpperCase() + BASE_CHAR_NUMBER_LOWER; + /** + *

获取随机字节数组

+ * + * @param length 长度 + * @return 随机字节数组 + */ + public final byte @NotNull [] randomBytes(int length) { + byte[] bytes = new byte[length]; + IntStream.range(0, length).forEach(i -> bytes[i] = (byte) (Math.random() * 256 - 128)); + return bytes; + } + + /** + *

获取32位随机字节数组

+ * + * @return 随机字节数组 + */ + public final byte @NotNull [] randomBytes() { + return randomBytes(32); + } /** *

获取32位随机字符串

@@ -76,17 +98,12 @@ public class RandomUtil { if (!StringUtils.hasText(baseString)) { return Constant.EMPTY_STRING; } - if (length < 1) { - length = 1; - } - - final StringBuilder sb = new StringBuilder(length); + length = Math.max(length, 1); final int baseLength = baseString.length(); - for (int i = 0; i < length; i++) { - final int number = randomInt(baseLength); - sb.append(baseString.charAt(number)); - } - return sb.toString(); + return IntStream.range(0, length) + .map(i -> randomInt(baseLength)) + .mapToObj(number -> String.valueOf(baseString.charAt(number))) + .collect(Collectors.joining()); } /** @@ -139,7 +156,11 @@ public class RandomUtil { return getRandom().nextInt(min, max); } - + /** + *

获得随机数种子

+ * + * @return 随机种子 + */ private ThreadLocalRandom getRandom() { return ThreadLocalRandom.current(); } diff --git a/airpower-core/src/main/java/cn/hamm/airpower/util/RsaUtil.java b/airpower-core/src/main/java/cn/hamm/airpower/util/RsaUtil.java index 3630ccc..7919df4 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/util/RsaUtil.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/util/RsaUtil.java @@ -12,10 +12,7 @@ import org.springframework.stereotype.Component; import javax.crypto.Cipher; import java.io.ByteArrayOutputStream; -import java.security.Key; -import java.security.KeyFactory; -import java.security.PrivateKey; -import java.security.PublicKey; +import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; @@ -58,11 +55,11 @@ public class RsaUtil { * @param sourceContent 原文 * @return 密文 */ - public final String publicKeyEncode(String sourceContent) { + public final String publicKeyEncrypt(String sourceContent) { try { int blockSize = CRYPT_KEY_SIZE / 8 - 11; PublicKey publicKey = getPublicKey(this.publicKey); - return encodeByKey(sourceContent, publicKey, blockSize); + return encrypt(sourceContent, publicKey, blockSize); } catch (Exception exception) { log.error(exception.getMessage(), exception); throw new ServiceException(exception); @@ -75,11 +72,11 @@ public class RsaUtil { * @param encryptedContent 密文 * @return 原文 */ - public final @NotNull String privateKeyDecode(String encryptedContent) { + public final @NotNull String privateKeyDecrypt(String encryptedContent) { try { int blockSize = CRYPT_KEY_SIZE / 8; PrivateKey privateKey = getPrivateKey(this.privateKey); - return decodeByKey(encryptedContent, privateKey, blockSize); + return decrypt(encryptedContent, privateKey, blockSize); } catch (Exception exception) { log.error(exception.getMessage(), exception); throw new ServiceException(exception); @@ -92,11 +89,11 @@ public class RsaUtil { * @param sourceContent 原文 * @return 密文 */ - public final String privateKeyEncode(String sourceContent) { + public final String privateKeyEncrypt(String sourceContent) { try { int blockSize = CRYPT_KEY_SIZE / 8 - 11; PrivateKey privateKey = getPrivateKey(this.privateKey); - return encodeByKey(sourceContent, privateKey, blockSize); + return encrypt(sourceContent, privateKey, blockSize); } catch (Exception exception) { log.error(exception.getMessage(), exception); throw new ServiceException(exception); @@ -110,11 +107,11 @@ public class RsaUtil { * @param encryptedContent 密文 * @return 原文 */ - public final @NotNull String publicKeyDecode(String encryptedContent) { + public final @NotNull String publicKeyDecrypt(String encryptedContent) { try { int blockSize = CRYPT_KEY_SIZE / 8; PublicKey publicKey = getPublicKey(this.publicKey); - return decodeByKey(encryptedContent, publicKey, blockSize); + return decrypt(encryptedContent, publicKey, blockSize); } catch (Exception exception) { log.error(exception.getMessage(), exception); throw new ServiceException(exception); @@ -130,7 +127,7 @@ public class RsaUtil { * @return 明文 */ @Contract("_, _, _ -> new") - private @NotNull String decodeByKey(String encryptedContent, Key key, int blockSize) throws Exception { + private @NotNull String decrypt(String encryptedContent, Key key, int blockSize) throws Exception { byte[] srcBytes = Base64.getDecoder().decode(encryptedContent); Cipher deCipher; deCipher = Cipher.getInstance(CRYPT_METHOD); @@ -148,7 +145,7 @@ public class RsaUtil { * @param blockSize 区块大小 * @return 密文 */ - private String encodeByKey(@NotNull String sourceContent, Key key, int blockSize) throws Exception { + private String encrypt(@NotNull String sourceContent, Key key, int blockSize) throws Exception { byte[] srcBytes = sourceContent.getBytes(); Cipher cipher; cipher = Cipher.getInstance(CRYPT_METHOD); @@ -212,4 +209,61 @@ public class RsaUtil { byteArrayOutputStream.close(); return data; } + + /** + *

生成RSA密钥对

+ * + * @return KeyPair + */ + public final KeyPair generateKeyPair() throws NoSuchAlgorithmException { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(2048); + return keyPairGenerator.generateKeyPair(); + } + + /** + *

将公钥转换为PEM格式

+ * + * @param publicKey 公钥 + * @return PEM + */ + public final @NotNull String convertPublicKeyToPEM(@NotNull PublicKey publicKey) { + byte[] encoded = publicKey.getEncoded(); + String base64Encoded = Base64.getEncoder().encodeToString(encoded); + return "-----BEGIN PUBLIC KEY-----\n" + + wrapBase64Text(base64Encoded) + + "-----END PUBLIC KEY-----"; + } + + /** + *

将私钥转换为PEM格式

+ * + * @param privateKey 私钥 + * @return PEM + */ + public final @NotNull String convertPrivateKeyToPEM(@NotNull PrivateKey privateKey) { + byte[] encoded = privateKey.getEncoded(); + String base64Encoded = Base64.getEncoder().encodeToString(encoded); + return "-----BEGIN RSA PRIVATE KEY-----\n" + + wrapBase64Text(base64Encoded) + + "-----END RSA PRIVATE KEY-----"; + } + + /** + *

将Base64编码的文本换行

+ * + * @param base64Text 原始Base64 + * @return 换行后的 + */ + private @NotNull String wrapBase64Text(@NotNull String base64Text) { + final int wrapLength = 64; + StringBuilder wrappedText = new StringBuilder(); + int start = 0; + while (start < base64Text.length()) { + int end = Math.min(start + wrapLength, base64Text.length()); + wrappedText.append(base64Text, start, end).append("\n"); + start = end; + } + return wrappedText.toString(); + } } diff --git a/airpower-core/src/main/java/cn/hamm/airpower/util/Utils.java b/airpower-core/src/main/java/cn/hamm/airpower/util/Utils.java index ad256a9..d570725 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/util/Utils.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/util/Utils.java @@ -157,6 +157,12 @@ public class Utils { @Getter private static StringUtil stringUtil; + /** + *

AES工具

+ */ + @Getter + private static AesUtil aesUtil; + /** *

获取HttpUtil

* @@ -201,7 +207,8 @@ public class Utils { HttpServletResponse httpServletResponse, NumberUtil numberUtil, StringUtil stringUtil, - WebsocketUtil websocketUtil + WebsocketUtil websocketUtil, + AesUtil aesUtil ) { Utils.redisUtil = redisUtil; Utils.emailUtil = emailUtil; @@ -226,6 +233,7 @@ public class Utils { Utils.numberUtil = numberUtil; Utils.stringUtil = stringUtil; Utils.websocketUtil = websocketUtil; + Utils.aesUtil = aesUtil; } /** -- Gitee