diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java index d7431b1..6cb0c47 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java @@ -721,4 +721,9 @@ public interface CommonConstant { * 多选 */ String PD = "PD"; + + /** + * url加解密密钥(AES) + */ + String URL_SECRET_KEY = "a3f8b2c1d4e5f6a7b8c9d0e1f2a3b4c5"; } diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/util/AesEncryptUtils.java b/jeecg-boot-base-core/src/main/java/org/jeecg/util/AesEncryptUtils.java new file mode 100644 index 0000000..ecc39a6 --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/util/AesEncryptUtils.java @@ -0,0 +1,110 @@ +package org.jeecg.util; + +import org.jeecg.common.constant.CommonConstant; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Base64; + +/** + * AES/CBC/PKCS5Padding 对称加密工具类 + * 加密结果经 Base64 URL Safe(无填充)编码,可安全用于 URL 传参 + */ +public class AesEncryptUtils { + + private static final String ALGORITHM = "AES"; + private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding"; + /** + * CBC 模式 IV 固定 16 字节 + */ + private static final int IV_LENGTH = 16; + + /** + * 加密 + * 随机生成 IV,将 [IV(16字节) + 密文] 拼接后进行 Base64 URL Safe(无填充)编码 + * + * @param plainText 明文字符串 + * @param secretKey 密钥(任意长度字符串,内部经 SHA-256 截取为 128 位) + * @return URL 安全的密文字符串,不含 +、/、= 等特殊字符 + * @throws Exception 加密异常 + */ + public static String encrypt(String plainText, String secretKey) throws Exception { + byte[] keyBytes = deriveKey(secretKey); + byte[] ivBytes = generateIv(); + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + cipher.init(Cipher.ENCRYPT_MODE, + new SecretKeySpec(keyBytes, ALGORITHM), + new IvParameterSpec(ivBytes)); + byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); + // 将 IV 前缀拼接到密文,解密时从头部分离 + byte[] combined = new byte[IV_LENGTH + encrypted.length]; + System.arraycopy(ivBytes, 0, combined, 0, IV_LENGTH); + System.arraycopy(encrypted, 0, combined, IV_LENGTH, encrypted.length); + return Base64.getUrlEncoder().withoutPadding().encodeToString(combined); + } + + /** + * 解密 + * 从密文头部分离 IV,再执行 AES/CBC 解密 + * + * @param cipherText URL 安全的密文字符串(由 encrypt 方法生成) + * @param secretKey 密钥(须与加密时保持一致) + * @return 解密后的明文字符串 + * @throws Exception 解密异常(密钥错误或数据被篡改时抛出) + */ + public static String decrypt(String cipherText, String secretKey) throws Exception { + byte[] combined = Base64.getUrlDecoder().decode(cipherText); + byte[] ivBytes = Arrays.copyOfRange(combined, 0, IV_LENGTH); + byte[] encrypted = Arrays.copyOfRange(combined, IV_LENGTH, combined.length); + byte[] keyBytes = deriveKey(secretKey); + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + cipher.init(Cipher.DECRYPT_MODE, + new SecretKeySpec(keyBytes, ALGORITHM), + new IvParameterSpec(ivBytes)); + return new String(cipher.doFinal(encrypted), StandardCharsets.UTF_8); + } + + /** + * 通过 SHA-256 对密钥字符串进行哈希,取前 16 字节作为 AES 128 位密钥 + * 支持任意长度的密钥输入,避免 AES 对密钥长度的严格限制 + * + * @param secretKey 原始密钥字符串 + * @return 16 字节的 AES 密钥 + */ + private static byte[] deriveKey(String secretKey) throws Exception { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(secretKey.getBytes(StandardCharsets.UTF_8)); + // 取前 16 字节 = 128 位 AES 密钥 + return Arrays.copyOf(hash, 16); + } + + /** + * 使用 SecureRandom 随机生成 16 字节 IV + * 每次加密使用不同 IV,防止相同明文产生相同密文 + * + * @return 16 字节随机 IV + */ + private static byte[] generateIv() { + byte[] iv = new byte[IV_LENGTH]; + new SecureRandom().nextBytes(iv); + return iv; + } + + public static void main(String[] args) { + try { + String plainText = "https://hello world"; + String secretKey = CommonConstant.URL_SECRET_KEY; +// String cipherText = AesEncryptUtils.encrypt(plainText, secretKey); +// System.out.println(cipherText); + String decryptedText = AesEncryptUtils.decrypt("6oFxHVMYNHXpz8VtsREcNlokVqOdvaZNSGBJ5U3_7mY", secretKey); + System.out.println(decryptedText); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/jeecg-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/bean/response/BaseEmployeeInfo.java b/jeecg-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/bean/response/BaseEmployeeInfo.java index bf288ef..1c50f4c 100644 --- a/jeecg-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/bean/response/BaseEmployeeInfo.java +++ b/jeecg-system/jeecg-system-api/jeecg-system-cloud-api/src/main/java/org/jeecg/bean/response/BaseEmployeeInfo.java @@ -82,18 +82,36 @@ public class BaseEmployeeInfo { @Schema(title = "二级部门Code(单位)") private String secondDeptCode; + @Schema(title = "二级部门id(单位)") + private String secondDeptId; + @Schema(title = "二级部门名称(单位)") private String secondDeptName; @Schema(title = "三级部门Code(部门)") private String thirdDeptCode; + @Schema(title = "三级部门id(部门)") + private String thirdDeptId; + @Schema(title = "三级部门名称(部门)") private String thirdDeptName; @Schema(title = "当前部门Code(用户所属部门)") private String thisDeptCode; + @Schema(title = "当前部门id(用户所属部门)") + private String thisDeptId; + @Schema(title = "当前部门名称(用户所属部门)") private String thisDeptName; + + @Schema(title = "角色编码") + private String roleCodes; + + @Schema(title = "管理部门(code)") + private String departCodes; + + @Schema(title = "管理部门(id)") + private String departIds; } diff --git a/jeecg-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SysApiController.java b/jeecg-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SysApiController.java index a13dc2a..d32e4a4 100644 --- a/jeecg-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SysApiController.java +++ b/jeecg-system/jeecg-system-biz/src/main/java/org/jeecg/modules/api/controller/SysApiController.java @@ -3,16 +3,20 @@ package org.jeecg.modules.api.controller; import org.jeecg.base.UserBase; import org.jeecg.bean.response.BaseEmployeeInfo; import org.jeecg.common.api.vo.Result; +import org.jeecg.common.constant.CommonConstant; import org.jeecg.modules.system.bean.response.ScalePersonalUserInfo; import org.jeecg.modules.system.service.ISysUserService; import org.jeecg.modules.system.service.ScalePersonalService; +import org.jeecg.util.AesEncryptUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @author stan @@ -67,5 +71,14 @@ public class SysApiController { return Result.ok(sysUserService.getUserInfo()); } + /** + * 字符串加密 + */ + @GetMapping("encryptInfo") + public Result> encryptInfo(@RequestParam String str) throws Exception { + Map map = new HashMap<>(); + map.put("encryptData", AesEncryptUtils.encrypt(str, CommonConstant.URL_SECRET_KEY)); + return Result.ok(map); + } } diff --git a/jeecg-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java b/jeecg-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java index 8d67cb0..7a986b7 100644 --- a/jeecg-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java +++ b/jeecg-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java @@ -3906,6 +3906,16 @@ public class SysUserServiceImpl extends ServiceImpl impl if (null == loginUser) { ExceptionAssertsUtil.fail("用户不存在!"); } + List managedCodes = GlobalUtils.getManagedCodes(null); + Set departIds = new HashSet<>(); + if (CollUtil.isNotEmpty(managedCodes)) { + managedCodes.forEach(s -> { + String departIdByOrgCode = sysCache.getDepartIdByOrgCode(s); + if (StringUtils.isNotBlank(departIdByOrgCode) && !"null".equals(departIdByOrgCode)) { + departIds.add(departIdByOrgCode); + } + }); + } MPJLambdaWrapper queryWrapper = new MPJLambdaWrapper() .selectAs(SysUser::getId, BaseEmployeeInfo::getUserId) .selectAs(SysUser::getUsername, BaseEmployeeInfo::getUserName) @@ -3931,13 +3941,19 @@ public class SysUserServiceImpl extends ServiceImpl impl baseEmployeeInfo.setAge(ObjectUtils.isNotEmpty(loginUser.getAge()) && loginUser.getAge() > 0 ? loginUser.getAge() : null); SysDepart secondDepart = sysCache.getDepartByOrgCode(GlobalUtils.getSecondDepartOrgCode(loginUser.getOrgCode())); baseEmployeeInfo.setSecondDeptCode(secondDepart.getOrgCode()); + baseEmployeeInfo.setSecondDeptId(secondDepart.getId()); baseEmployeeInfo.setSecondDeptName(secondDepart.getDepartName()); SysDepart thirdDepart = sysCache.getDepartByOrgCode(GlobalUtils.getThirdDepartOrgCode(loginUser.getOrgCode())); baseEmployeeInfo.setThirdDeptCode(thirdDepart.getOrgCode()); + baseEmployeeInfo.setThirdDeptId(thirdDepart.getId()); baseEmployeeInfo.setThirdDeptName(thirdDepart.getDepartName()); baseEmployeeInfo.setThisDeptCode(loginUser.getOrgCode()); SysDepart departByOrgCode = sysCache.getDepartByOrgCode(loginUser.getOrgCode()); baseEmployeeInfo.setThisDeptName(departByOrgCode.getDepartName()); + baseEmployeeInfo.setThisDeptId(departByOrgCode.getId()); + baseEmployeeInfo.setRoleCodes(loginUser.getRoleCodes()); + baseEmployeeInfo.setDepartCodes(String.join(",", managedCodes)); + baseEmployeeInfo.setDepartIds(String.join(",", departIds)); return baseEmployeeInfo; } }