From 7065aa06480e5d8049090d65e5d020e9c5ff8f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A7=9C=E7=8E=89=E7=90=A6?= <7507756+jiang_yuqi@user.noreply.gitee.com> Date: Sat, 13 Jan 2024 22:30:18 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/LabourApiController.java | 82 ++-- .../system/SysApplyConfigController.java | 12 + .../ruoyi/common/enums/HttpStatusEnum.java | 36 ++ .../com/ruoyi/common/enums/ShiFouEnum.java | 38 ++ .../java/com/ruoyi/common/utils/NoUtils.java | 33 ++ .../com/ruoyi/common/utils/StringUtils.java | 31 +- .../com/ruoyi/common/utils/sign/RSAUtil.java | 356 ++++++++++++++++++ .../ruoyi/system/domain/SysApplyConfig.java | 8 + .../impl/SysApplyConfigServiceImpl.java | 15 + .../mapper/system/SysApplyConfigMapper.xml | 17 +- ruoyi-ui/src/api/system/applyConfig.js | 8 + .../src/views/system/applyConfig/index.vue | 144 +++++-- 12 files changed, 707 insertions(+), 73 deletions(-) create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpStatusEnum.java create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/enums/ShiFouEnum.java create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/utils/NoUtils.java create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/RSAUtil.java diff --git a/ruoyi-admin/src/main/java/com/ruoyi/api/labour/controller/LabourApiController.java b/ruoyi-admin/src/main/java/com/ruoyi/api/labour/controller/LabourApiController.java index 5aa4c503..f0d65f97 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/api/labour/controller/LabourApiController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/api/labour/controller/LabourApiController.java @@ -12,8 +12,11 @@ import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.text.Convert; +import com.ruoyi.common.enums.HttpStatusEnum; import com.ruoyi.common.enums.LimitType; +import com.ruoyi.common.enums.ShiFouEnum; import com.ruoyi.common.enums.UserTypeEnum; +import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.AuthRsaUtils; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; @@ -81,14 +84,17 @@ public class LabourApiController extends BaseController { public AjaxResult getToken(@Validated @RequestBody TokenReqVo req) { SysApplyConfig sysApplyConfig = redisCache.getCacheObject(CacheConstants.YANZHU_SYSTEM_CONFIG+req.getAppId()); if(sysApplyConfig==null){ - throw new RuntimeException("AppId不存在或已被停用"); + throw new ServiceException(HttpStatusEnum.ERROR.getInfo(),HttpStatusEnum.ERROR.getCode()); + } + if(StringUtils.equals(ShiFouEnum.SHI.getCode()+"",sysApplyConfig.getIsDel())){ + throw new ServiceException(HttpStatusEnum.DISABLE.getInfo(),HttpStatusEnum.DISABLE.getCode()); } AjaxResult ajax = AjaxResult.success(); String systemToken = ""; if (req.getLoginSign(sysApplyConfig.getPrivateKey())) { systemToken = this.getAppIdLoginToken(req.getAppId(),sysApplyConfig); } else { - throw new RuntimeException("签名值不合法"); + throw new ServiceException(HttpStatusEnum.SINGET_ERROR.getInfo(),HttpStatusEnum.SINGET_ERROR.getCode()); } ajax.put("systemToken", systemToken); return ajax; @@ -136,6 +142,9 @@ public class LabourApiController extends BaseController { SysApplyConfig sysApplyConfig = redisCache.getCacheObject(CacheConstants.YANZHU_SYSTEM_CONFIG+super.getUsername()); if(req.checkTimestamp()){ try { + if(StringUtils.equals(ShiFouEnum.SHI.getCode()+"",sysApplyConfig.getIsDel())){ + throw new ServiceException(HttpStatusEnum.DISABLE.getInfo(),HttpStatusEnum.DISABLE.getCode()); + } String result = AuthRsaUtils.decryptByPrivateKey(sysApplyConfig.getPrivateKey(),req.getSign()); SurProjectAttendanceGroup surProjectAttendanceGroup = JSONObject.parseObject(result, SurProjectAttendanceGroup.class); if(StringUtils.isNotEmpty(surProjectAttendanceGroup.getServerid())){ @@ -157,13 +166,13 @@ public class LabourApiController extends BaseController { surProjectAttendanceGroupService.insertSurProjectAttendanceGroup(surProjectAttendanceGroup); } }else{ - throw new RuntimeException("数据解析异常"); + throw new ServiceException(HttpStatusEnum.DARA_EXCEPTION.getInfo(),HttpStatusEnum.DARA_EXCEPTION.getCode()); } }catch (Exception e){ - throw new RuntimeException("签名解密异常"); + throw new ServiceException(HttpStatusEnum.SINGET_EXCEPTION.getInfo(),HttpStatusEnum.SINGET_EXCEPTION.getCode()); } }else{ - throw new RuntimeException("数据已过期"); + throw new ServiceException(HttpStatusEnum.SINGET_TIMEOUT.getInfo(),HttpStatusEnum.SINGET_TIMEOUT.getCode()); } return success(); } @@ -179,11 +188,14 @@ public class LabourApiController extends BaseController { @RateLimiter(time = 30, count = 10, limitType = LimitType.IP) @PostMapping("/v1/pushLabourGroupList") public AjaxResult pushLabourGroupList(@Validated @RequestBody LabourSignetVo req) { + // 失败集合 + List failServiceIdList = new ArrayList<>(); SysApplyConfig sysApplyConfig = redisCache.getCacheObject(CacheConstants.YANZHU_SYSTEM_CONFIG+super.getUsername()); if(req.checkTimestamp()){ try { - // 失败集合 - List failServiceIdList = new ArrayList<>(); + if(StringUtils.equals(ShiFouEnum.SHI.getCode()+"",sysApplyConfig.getIsDel())){ + throw new ServiceException(HttpStatusEnum.DISABLE.getInfo(),HttpStatusEnum.DISABLE.getCode()); + } // 保存集合 List saveList = new ArrayList<>(); String result = AuthRsaUtils.decryptByPrivateKey(sysApplyConfig.getPrivateKey(),req.getSign()); @@ -207,15 +219,15 @@ public class LabourApiController extends BaseController { } surProjectAttendanceGroupService.batchSurProjectAttendanceGroup(saveList); }else{ - throw new RuntimeException("数据解析异常"); + throw new ServiceException(HttpStatusEnum.DARA_EXCEPTION.getInfo(),HttpStatusEnum.DARA_EXCEPTION.getCode()); } }catch (Exception e){ - throw new RuntimeException("签名解密异常"); + throw new ServiceException(HttpStatusEnum.SINGET_EXCEPTION.getInfo(),HttpStatusEnum.SINGET_EXCEPTION.getCode()); } }else{ - throw new RuntimeException("数据已过期"); + throw new ServiceException(HttpStatusEnum.SINGET_TIMEOUT.getInfo(),HttpStatusEnum.SINGET_TIMEOUT.getCode()); } - return success(); + return success(failServiceIdList); } /** @@ -232,6 +244,9 @@ public class LabourApiController extends BaseController { SysApplyConfig sysApplyConfig = redisCache.getCacheObject(CacheConstants.YANZHU_SYSTEM_CONFIG+super.getUsername()); if(req.checkTimestamp()){ try { + if(StringUtils.equals(ShiFouEnum.SHI.getCode()+"",sysApplyConfig.getIsDel())){ + throw new ServiceException(HttpStatusEnum.DISABLE.getInfo(),HttpStatusEnum.DISABLE.getCode()); + } String result = AuthRsaUtils.decryptByPrivateKey(sysApplyConfig.getPrivateKey(),req.getSign()); SurProjectAttendanceUser surProjectAttendanceUser = JSONObject.parseObject(result, SurProjectAttendanceUser.class); if(StringUtils.isNotEmpty(surProjectAttendanceUser.getWorkerId())){ @@ -253,13 +268,13 @@ public class LabourApiController extends BaseController { surProjectAttendanceUserService.insertSurProjectAttendanceUser(surProjectAttendanceUser); } }else{ - throw new RuntimeException("数据解析异常"); + throw new ServiceException(HttpStatusEnum.DARA_EXCEPTION.getInfo(),HttpStatusEnum.DARA_EXCEPTION.getCode()); } }catch (Exception e){ - throw new RuntimeException("签名解密异常"); + throw new ServiceException(HttpStatusEnum.SINGET_EXCEPTION.getInfo(),HttpStatusEnum.SINGET_EXCEPTION.getCode()); } }else{ - throw new RuntimeException("数据已过期"); + throw new ServiceException(HttpStatusEnum.SINGET_TIMEOUT.getInfo(),HttpStatusEnum.SINGET_TIMEOUT.getCode()); } return success(); } @@ -275,11 +290,14 @@ public class LabourApiController extends BaseController { @RateLimiter(time = 30, count = 10, limitType = LimitType.IP) @PostMapping("/v1/pushLabourUserList") public AjaxResult pushLabourUserList(@Validated @RequestBody LabourSignetVo req) { + // 失败集合 + List failServiceIdList = new ArrayList<>(); SysApplyConfig sysApplyConfig = redisCache.getCacheObject(CacheConstants.YANZHU_SYSTEM_CONFIG+super.getUsername()); if(req.checkTimestamp()){ try { - // 失败集合 - List failServiceIdList = new ArrayList<>(); + if(StringUtils.equals(ShiFouEnum.SHI.getCode()+"",sysApplyConfig.getIsDel())){ + throw new ServiceException(HttpStatusEnum.DISABLE.getInfo(),HttpStatusEnum.DISABLE.getCode()); + } // 保存集合 List saveList = new ArrayList<>(); String result = AuthRsaUtils.decryptByPrivateKey(sysApplyConfig.getPrivateKey(),req.getSign()); @@ -303,15 +321,15 @@ public class LabourApiController extends BaseController { } surProjectAttendanceUserService.batchSurProjectAttendanceUser(saveList); }else{ - throw new RuntimeException("数据解析异常"); + throw new ServiceException(HttpStatusEnum.DARA_EXCEPTION.getInfo(),HttpStatusEnum.DARA_EXCEPTION.getCode()); } }catch (Exception e){ - throw new RuntimeException("签名解密异常"); + throw new ServiceException(HttpStatusEnum.SINGET_EXCEPTION.getInfo(),HttpStatusEnum.SINGET_EXCEPTION.getCode()); } }else{ - throw new RuntimeException("数据已过期"); + throw new ServiceException(HttpStatusEnum.SINGET_TIMEOUT.getInfo(),HttpStatusEnum.SINGET_TIMEOUT.getCode()); } - return success(); + return success(failServiceIdList); } /** @@ -328,6 +346,9 @@ public class LabourApiController extends BaseController { SysApplyConfig sysApplyConfig = redisCache.getCacheObject(CacheConstants.YANZHU_SYSTEM_CONFIG+super.getUsername()); if(req.checkTimestamp()){ try { + if(StringUtils.equals(ShiFouEnum.SHI.getCode()+"",sysApplyConfig.getIsDel())){ + throw new ServiceException(HttpStatusEnum.DISABLE.getInfo(),HttpStatusEnum.DISABLE.getCode()); + } String result = AuthRsaUtils.decryptByPrivateKey(sysApplyConfig.getPrivateKey(),req.getSign()); SurProjectAttendanceData surProjectAttendanceData = JSONObject.parseObject(result, SurProjectAttendanceData.class); if(StringUtils.isNotEmpty(surProjectAttendanceData.getWorkerId()) && StringUtils.isNotEmpty(surProjectAttendanceData.getServerid())){ @@ -350,13 +371,13 @@ public class LabourApiController extends BaseController { surProjectAttendanceDataService.insertSurProjectAttendanceData(surProjectAttendanceData); } }else{ - throw new RuntimeException("数据解析异常"); + throw new ServiceException(HttpStatusEnum.DARA_EXCEPTION.getInfo(),HttpStatusEnum.DARA_EXCEPTION.getCode()); } }catch (Exception e){ - throw new RuntimeException("签名解密异常"); + throw new ServiceException(HttpStatusEnum.SINGET_EXCEPTION.getInfo(),HttpStatusEnum.SINGET_EXCEPTION.getCode()); } }else{ - throw new RuntimeException("数据已过期"); + throw new ServiceException(HttpStatusEnum.SINGET_TIMEOUT.getInfo(),HttpStatusEnum.SINGET_TIMEOUT.getCode()); } return success(); } @@ -372,11 +393,14 @@ public class LabourApiController extends BaseController { @RateLimiter(time = 30, count = 10, limitType = LimitType.IP) @PostMapping("/v1/pushLabourDataList") public AjaxResult pushLabourDataList(@Validated @RequestBody LabourSignetVo req) { + // 失败集合 + List failServiceIdList = new ArrayList<>(); SysApplyConfig sysApplyConfig = redisCache.getCacheObject(CacheConstants.YANZHU_SYSTEM_CONFIG+super.getUsername()); if(req.checkTimestamp()){ try { - // 失败集合 - List failServiceIdList = new ArrayList<>(); + if(StringUtils.equals(ShiFouEnum.SHI.getCode()+"",sysApplyConfig.getIsDel())){ + throw new ServiceException(HttpStatusEnum.DISABLE.getInfo(),HttpStatusEnum.DISABLE.getCode()); + } // 保存集合 List saveList = new ArrayList<>(); String result = AuthRsaUtils.decryptByPrivateKey(sysApplyConfig.getPrivateKey(),req.getSign()); @@ -400,15 +424,15 @@ public class LabourApiController extends BaseController { } surProjectAttendanceDataService.batchSurProjectAttendanceData(saveList); }else{ - throw new RuntimeException("数据解析异常"); + throw new ServiceException(HttpStatusEnum.DARA_EXCEPTION.getInfo(),HttpStatusEnum.DARA_EXCEPTION.getCode()); } }catch (Exception e){ - throw new RuntimeException("签名解密异常"); + throw new ServiceException(HttpStatusEnum.SINGET_EXCEPTION.getInfo(),HttpStatusEnum.SINGET_EXCEPTION.getCode()); } }else{ - throw new RuntimeException("数据已过期"); + throw new ServiceException(HttpStatusEnum.SINGET_TIMEOUT.getInfo(),HttpStatusEnum.SINGET_TIMEOUT.getCode()); } - return success(); + return success(failServiceIdList); } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysApplyConfigController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysApplyConfigController.java index b6c37db4..470c85ac 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysApplyConfigController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysApplyConfigController.java @@ -5,6 +5,7 @@ import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.NoUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.system.domain.SysApplyConfig; import com.ruoyi.system.service.ISysApplyConfigService; @@ -95,4 +96,15 @@ public class SysApplyConfigController extends BaseController { return toAjax(sysApplyConfigService.deleteSysApplyConfigByIds(ids)); } + + /** + * 生成AppId + */ + @PreAuthorize("@ss.hasPermi('system:applyConfig:add')") + @GetMapping("/createAppId") + public AjaxResult createAppId() + { + return success(NoUtils.createAppId()); + } + } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpStatusEnum.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpStatusEnum.java new file mode 100644 index 00000000..90274890 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpStatusEnum.java @@ -0,0 +1,36 @@ +package com.ruoyi.common.enums; + +/** + * 订单Http状态 + * + * @author JiangYuQi + */ +public enum HttpStatusEnum { + + ERROR(11110, "AppId不存在或已被停用"), + DISABLE(11112, "AppId已被停用"), + SINGET_ERROR(11113, "签名值不正确"), + SINGET_TIMEOUT(11114, "签名数据已过期"), + SINGET_EXCEPTION(11115, "签名数据解密异常"), + DARA_EXCEPTION(11116, "数据解析异常"); + + private final Integer code; + private final String info; + + HttpStatusEnum(Integer code, String info) + { + this.code = code; + this.info = info; + } + + public Integer getCode() + { + return code; + } + + public String getInfo() + { + return info; + } + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/ShiFouEnum.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/ShiFouEnum.java new file mode 100644 index 00000000..39dd58ac --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/ShiFouEnum.java @@ -0,0 +1,38 @@ +package com.ruoyi.common.enums; + +import com.ruoyi.common.core.text.Convert; + +/** + * 是否状态 + * + * @author JiangYuQi + */ +public enum ShiFouEnum { + + FOU(0, "否"), SHI(1, "是"); + + private final Integer code; + private final String info; + + ShiFouEnum(Integer code, String info) + { + this.code = code; + this.info = info; + } + + public Integer getCode() + { + return code; + } + + public String getInfo() + { + return info; + } + + public Long getLongCode() + { + return Convert.toLong(code); + } + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/NoUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/NoUtils.java new file mode 100644 index 00000000..db6d06c6 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/NoUtils.java @@ -0,0 +1,33 @@ +package com.ruoyi.common.utils; + +/** + * 编号工具类 + * + * @author JiangYuQi + * @date 2023-11-07 + */ +public class NoUtils { + + private static final String PREFIX = "jhcf"; + private static int COUNTER = 0; + + /** + * 生成appId + * + * @author JiangYuQi + * @date 2023-11-07 + */ + public static String createAppId() { + long timestamp = System.currentTimeMillis(); + String sequencePart = String.format("%03d", getContractNextSequence()); + return PREFIX + timestamp+ StringUtils.randomString(10) + sequencePart; + } + + private static synchronized int getContractNextSequence() { + if (COUNTER >= 999) { + COUNTER = 0; + } + return ++COUNTER; + } + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java index e683d54f..e4992e47 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java @@ -1,11 +1,7 @@ package com.ruoyi.common.utils; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; + import org.springframework.util.AntPathMatcher; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.text.StrFormatter; @@ -611,4 +607,27 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils } return sb.toString(); } + + private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; + + /** + * 获取随机字符串 + * + * @param length 长度 + * @return 返回指定长度的随机字符串。 + */ + public static String randomString(int length) { + if (length < 1) { + length = 1; + } + StringBuilder sb = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < length; i++) { + int randomIndex = random.nextInt(CHARACTERS.length()); + char randomChar = CHARACTERS.charAt(randomIndex); + sb.append(randomChar); + } + String randomString = sb.toString(); + return randomString; + } } \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/RSAUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/RSAUtil.java new file mode 100644 index 00000000..3745d405 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/RSAUtil.java @@ -0,0 +1,356 @@ +package com.ruoyi.common.utils.sign; + +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; + +/** + * @description: Rsa非对称加密算法工具类 + * @author: JiangYuQi + * @date: 2024/1/13 15:14 + */ +public final class RSAUtil { + + private RSAUtil() {} + + private static final String RSA = "RSA"; + + private static final String SIGN_ALGORITHMS = "SHA1WithRSA"; + + private static final Base64.Decoder DECODER = Base64.getDecoder(); + + private static final Base64.Encoder ENCODER = Base64.getEncoder(); + + + public static void main(String[] args) throws NoSuchAlgorithmException { + // 生成密钥对 + KeyPair keyPair = getKeyPair(); + // 公匙 + String publicKey = getPublicKeyBase64(keyPair); + System.out.println("公匙 -> " + publicKey); + // 私匙 + String privateKey = getPrivateKeyBase64(keyPair); + System.out.println("私匙 -> " + privateKey); + // 明文 + String plaintext = "hello world!"; + System.out.println("明文 -> " + plaintext); + // 密文base64(公匙加密) + String ciphertext = publicKeyEncrypt(plaintext, publicKey); + System.out.println("密文base64 -> " + ciphertext); + // 解密后明文(私匙解密) + String decryptString = privateKeyDecrypt(ciphertext, privateKey); + System.out.println("解密后明文 -> " + decryptString); + // 数字签名 +// String sign = sign(ciphertext, privateKey); +// System.out.println("数字签名 -> " + decryptString); +// // 验证签名 +// boolean pass = verify(ciphertext, sign, publicKey); +// System.out.println("验证签名 -> " + pass); + } + + + /** + * 生成秘钥对 + * + * @return + * @throws Exception + */ + public static KeyPair getKeyPair() throws NoSuchAlgorithmException { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA); + keyPairGenerator.initialize(2048); + return keyPairGenerator.generateKeyPair(); + } + + /** + * 获取公钥(Base64编码) + * + * @param keyPair 秘钥对 + * @return + */ + public static String getPublicKeyBase64(KeyPair keyPair) { + PublicKey publicKey = keyPair.getPublic(); + byte[] bytes = publicKey.getEncoded(); + // 先用base64编码,再转换为字符串 + return new String(ENCODER.encode(bytes), StandardCharsets.UTF_8); + } + + /** + * 获取私钥(Base64编码) + * + * @param keyPair 秘钥对 + * @return + */ + public static String getPrivateKeyBase64(KeyPair keyPair) { + PrivateKey privateKey = keyPair.getPrivate(); + byte[] bytes = privateKey.getEncoded(); + // 先用base64编码,再转换为字符串 + return new String(ENCODER.encode(bytes), StandardCharsets.UTF_8); + } + + /** + * 将Base64编码后的公钥转换成PublicKey对象 + * + * @param publicKeyBase64 公钥base64 + * @return + */ + public static PublicKey getPublicKey(String publicKeyBase64) throws NoSuchAlgorithmException, InvalidKeySpecException { + byte[] keyBytes = DECODER.decode(publicKeyBase64); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(RSA); + return keyFactory.generatePublic(keySpec); + } + + /** + * 将Base64编码后的私钥转换成PrivateKey对象 + * + * @param privateKeyBase64 私钥base64 + * @return + * @throws Exception + */ + public static PrivateKey getPrivateKey(String privateKeyBase64) throws NoSuchAlgorithmException, InvalidKeySpecException { + byte[] keyBytes = DECODER.decode((privateKeyBase64)); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(RSA); + return keyFactory.generatePrivate(keySpec); + } + + /** + * 公钥加密 + * + * @param plaintext 明文 + * @param publicKeyBase64 公钥base64 + * @return 密文数组base64编码后的字符串 + */ + public static String publicKeyEncrypt(String plaintext, String publicKeyBase64) { + try { + // 获取明文字节数组 + byte[] bytes = plaintext.getBytes(StandardCharsets.UTF_8); + Cipher cipher = Cipher.getInstance(RSA); + // 编码前设定编码方式及密钥 + PublicKey publicKey = getPublicKey(publicKeyBase64); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + int keyBit = getKeySize(publicKey); + int inputLen = bytes.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + int step = keyBit / 8 - 11; + for (int i = 0; inputLen - offSet > 0; offSet = i * step) { + byte[] cache; + if (inputLen - offSet > step) { + cache = cipher.doFinal(bytes, offSet, step); + } else { + cache = cipher.doFinal(bytes, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + ++i; + } + // 密文字节数组 + byte[] ciphertextBytes = out.toByteArray(); + out.close(); + // 返回密文字节数组base64编码后的字符串 + return new String(ENCODER.encode(ciphertextBytes), StandardCharsets.UTF_8); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 公钥解密 + * + * @param ciphertext 密文 + * @param publicKeyBase64 公钥base64 + * @return 明文 + */ + public static String publicKeyDecrypt(String ciphertext, String publicKeyBase64) { + try { + // 密文base64解码字节数组 + byte[] bytes = DECODER.decode(ciphertext.getBytes(StandardCharsets.UTF_8)); + Cipher cipher = Cipher.getInstance(RSA); + PublicKey publicKey = getPublicKey(publicKeyBase64); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + int keyBit = getKeySize(publicKey); + int inputLen = bytes.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + int step = keyBit / 8; + + for (int i = 0; inputLen - offSet > 0; offSet = i * step) { + byte[] cache; + if (inputLen - offSet > step) { + cache = cipher.doFinal(bytes, offSet, step); + } else { + cache = cipher.doFinal(bytes, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + ++i; + } + // 明文字节数组 + byte[] plaintextBytes = out.toByteArray(); + out.close(); + return new String(plaintextBytes, StandardCharsets.UTF_8); + } catch (Exception e) { + return null; + } + } + + /** + * 私钥加密 + * + * @param plaintext 明文 + * @param privateKeyBase64 私钥base64 + * @return + */ + public static String privateKeyEncrypt(String plaintext, String privateKeyBase64) { + try { + // 获取明文字节数组 + byte[] bytes = plaintext.getBytes(StandardCharsets.UTF_8); + Cipher cipher = Cipher.getInstance(RSA); + // 编码前设定编码方式及密钥 + PrivateKey privateKey = getPrivateKey(privateKeyBase64); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + int keyBit = getKeySize(privateKey); + int inputLen = bytes.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + int step = keyBit / 8 - 11; + + for (int i = 0; inputLen - offSet > 0; offSet = i * step) { + byte[] cache; + if (inputLen - offSet > step) { + cache = cipher.doFinal(bytes, offSet, step); + } else { + cache = cipher.doFinal(bytes, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + ++i; + } + // 密文字节数组 + byte[] ciphertextBytes = out.toByteArray(); + out.close(); + // 返回密文字节数组base64编码后的字符串 + return new String(ENCODER.encode(ciphertextBytes), StandardCharsets.UTF_8); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 私钥解密 + * + * @param ciphertext 密文 + * @param privateKeyBase64 私钥base64 + * @return 明文 + */ + public static String privateKeyDecrypt(String ciphertext, String privateKeyBase64) { + try { + // 密文base64解码字节数组 + byte[] bytes = DECODER.decode(ciphertext.getBytes(StandardCharsets.UTF_8)); + Cipher cipher = Cipher.getInstance(RSA); + PrivateKey privateKey = getPrivateKey(privateKeyBase64); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + int keyBit = getKeySize(privateKey); + int inputLen = bytes.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + int step = keyBit / 8; + + for (int i = 0; inputLen - offSet > 0; offSet = i * step) { + byte[] cache; + if (inputLen - offSet > step) { + cache = cipher.doFinal(bytes, offSet, step); + } else { + cache = cipher.doFinal(bytes, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + ++i; + } + // 明文字节数组 + byte[] plaintextBytes = out.toByteArray(); + out.close(); + return new String(plaintextBytes, StandardCharsets.UTF_8); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 使用私钥对数据进行数字签名 + * + * @param ciphertext 密文 + * @param privateKeyBase64 私钥Base64 + * @return 加密后的base64签名 + */ + public static String sign(String ciphertext, String privateKeyBase64) { + try { + // 密文字节数组 + byte[] ciphertextBytes = DECODER.decode(ciphertext.getBytes(StandardCharsets.UTF_8)); + PrivateKey privateKey = getPrivateKey(privateKeyBase64); + Signature signature = Signature.getInstance(SIGN_ALGORITHMS); + signature.initSign(privateKey); + signature.update(ciphertextBytes); + byte[] signed = signature.sign(); + return new String(ENCODER.encode(signed), StandardCharsets.UTF_8); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 使用公钥验证数字签名 + * + * @param ciphertext 密文 + * @param sign 签名 + * @param publicKeyBase64 公钥base64 + * @return 是否篡改了数据 + */ + public static boolean verify(String ciphertext, String sign, String publicKeyBase64) { + try { + // 密文base64解码字节数组 + byte[] ciphertextBytes = DECODER.decode(ciphertext.getBytes(StandardCharsets.UTF_8)); + // 签名base64解码字节数组 + byte[] signBytes = DECODER.decode(sign.getBytes(StandardCharsets.UTF_8)); + PublicKey publicKey = getPublicKey(publicKeyBase64); + Signature signature = Signature.getInstance(SIGN_ALGORITHMS); + signature.initVerify(publicKey); + signature.update(ciphertextBytes); + return signature.verify(signBytes); + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + /** + * 获取公钥长度 + * + * @param publicKey 公钥 + * @return + */ + public static int getKeySize(PublicKey publicKey) { + RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; + return rsaPublicKey.getModulus().bitLength(); + } + + /** + * 获取私钥长度 + * + * @param privateKey 私钥 + * @return + */ + public static int getKeySize(PrivateKey privateKey) { + RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey; + return rsaPrivateKey.getModulus().bitLength(); + } + +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysApplyConfig.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysApplyConfig.java index f87d24be..ba4d2da9 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysApplyConfig.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysApplyConfig.java @@ -32,10 +32,18 @@ public class SysApplyConfig extends BaseEntity @Excel(name = "项目主键") private Long projectId; + /** 项目名称 */ + @Excel(name = "项目名称") + private Long projectName; + /** 部门主键 */ @Excel(name = "部门主键") private Long deptId; + /** 部门名称 */ + @Excel(name = "部门名称") + private Long deptName; + /** 是否删除 */ @Excel(name = "是否删除") private String isDel; diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysApplyConfigServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysApplyConfigServiceImpl.java index 232d1fd0..6d6a215a 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysApplyConfigServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysApplyConfigServiceImpl.java @@ -1,10 +1,13 @@ package com.ruoyi.system.service.impl; +import java.security.KeyPair; import java.util.List; import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.core.redis.RedisCache; +import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.sign.RSAUtil; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -88,6 +91,18 @@ public class SysApplyConfigServiceImpl implements ISysApplyConfigService { sysApplyConfig.setCreateBy(SecurityUtils.getUsername()); sysApplyConfig.setCreateTime(DateUtils.getNowDate()); + try { + // 生成密钥对 + KeyPair keyPair = RSAUtil.getKeyPair(); + // 公匙 + String publicKey = RSAUtil.getPublicKeyBase64(keyPair); + sysApplyConfig.setPublicKey(publicKey); + // 私匙 + String privateKey = RSAUtil.getPrivateKeyBase64(keyPair); + sysApplyConfig.setPrivateKey(privateKey); + }catch (Exception e){ + throw new ServiceException(); + } int res = sysApplyConfigMapper.insertSysApplyConfig(sysApplyConfig); if(res>0){ this.loadingSysApplyConfigCache(); diff --git a/ruoyi-system/src/main/resources/mapper/system/SysApplyConfigMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysApplyConfigMapper.xml index 41fb60b1..3078e997 100644 --- a/ruoyi-system/src/main/resources/mapper/system/SysApplyConfigMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/SysApplyConfigMapper.xml @@ -10,7 +10,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + @@ -20,22 +22,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select id, app_id, public_key, private_key, project_id, dept_id, is_del, create_by, create_time, update_by, update_time, remark from sys_apply_config + select sac.id, sac.app_id, sac.public_key, sac.private_key, sac.project_id, sp.projectName, sac.dept_id, sd.dept_name as deptName, sac.is_del, sac.create_by, sac.create_time, sac.update_by, sac.update_time, sac.remark from sys_apply_config sac + left join sur_project sp on sac.project_id = sp.id + left join sys_dept sd on sac.dept_id = sd.dept_id diff --git a/ruoyi-ui/src/api/system/applyConfig.js b/ruoyi-ui/src/api/system/applyConfig.js index e286dbaf..333e368f 100644 --- a/ruoyi-ui/src/api/system/applyConfig.js +++ b/ruoyi-ui/src/api/system/applyConfig.js @@ -42,3 +42,11 @@ export function delApplyConfig(id) { method: 'delete' }) } + +// 生成有效的AppId +export function getApplyId() { + return request({ + url: '/system/applyConfig/createAppId', + method: 'get' + }) +} diff --git a/ruoyi-ui/src/views/system/applyConfig/index.vue b/ruoyi-ui/src/views/system/applyConfig/index.vue index 5020cfdd..85d65031 100644 --- a/ruoyi-ui/src/views/system/applyConfig/index.vue +++ b/ruoyi-ui/src/views/system/applyConfig/index.vue @@ -9,18 +9,18 @@ @keyup.enter.native="handleQuery" /> - + - + @@ -28,7 +28,7 @@ @@ -132,35 +132,66 @@ /> - + +
+

“应用公钥” 在注册应用后由系统生成,请在保存后查看。

+
- + - - + + - - - - - - - - - - - + + + + + +
+

“单位信息” 只能选择“总包单位”

+
+ + + + + + + + + - - + +