diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/businessdatasyn/executor/BusinessDataSyncScheduler.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/businessdatasyn/executor/BusinessDataSyncScheduler.java index 3be6d861..221e6deb 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/businessdatasyn/executor/BusinessDataSyncScheduler.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/businessdatasyn/executor/BusinessDataSyncScheduler.java @@ -59,6 +59,10 @@ public class BusinessDataSyncScheduler { log.warn("[BizSync] 配置不存在: {}", configKey); return; } + if (!config.isEnabled()) { + log.warn("[BizSync] 配置已禁用, 跳过手动同步: {}", configKey); + return; + } tableSyncExecutor.runOneTable(config, false); } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnforcementRegistrationController.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnforcementRegistrationController.java index 1fe84e3b..2d6df40a 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnforcementRegistrationController.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnforcementRegistrationController.java @@ -90,7 +90,6 @@ public class AppEnforcementRegistrationController extends BaseController { @PostMapping("/add") @ResponseBody @RepeatSubmit() - @Log(title = "行政执法登记", businessType = BusinessType.INSERT) public R addSave(@RequestBody EnforcementRegistrationBo bo) { if (StringUtils.isNotEmpty(bo.getId())) { @@ -201,7 +200,6 @@ public class AppEnforcementRegistrationController extends BaseController { @PostMapping("/edit") @ResponseBody @RepeatSubmit() - @Log(title = "行政执法登记", businessType = BusinessType.UPDATE) public R editSave(@RequestBody EnforcementRegistrationBo bo) { int resNum = 0; @@ -238,7 +236,6 @@ public class AppEnforcementRegistrationController extends BaseController { @PostMapping("/editInfo") @ResponseBody @RepeatSubmit() - @Log(title = "行政执法登记", businessType = BusinessType.UPDATE) public R editInfo(@RequestBody EnforcementRegistrationBo bo) { bo.setIsSubmit(0L); diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppNonEnforcementRegistrationController.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppNonEnforcementRegistrationController.java index 0defd010..989607e6 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppNonEnforcementRegistrationController.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppNonEnforcementRegistrationController.java @@ -28,7 +28,6 @@ public class AppNonEnforcementRegistrationController extends BaseController { */ @PostMapping("/add") @ResponseBody - @Log(title = "非行政执法登记", businessType = BusinessType.INSERT) public R addSave(@RequestBody NonEnforcementRegistrationBo bo) { diff --git a/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/controller/system/CryptoSensitiveController.java b/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/controller/system/CryptoSensitiveController.java new file mode 100644 index 00000000..e2c6e03c --- /dev/null +++ b/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/controller/system/CryptoSensitiveController.java @@ -0,0 +1,58 @@ +package org.dromara.system.controller.system; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.service.ICryptoSensitiveHsmService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +/** + * 密评数据管理 + * + * @author zrb + */ +@Slf4j +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/cryptoSensitive") +public class CryptoSensitiveController extends BaseController { + + private final ICryptoSensitiveHsmService cryptoSensitiveHsmService; + + /** + * 初始化 sys_user 历史存量数据到 crypto_sensitive_data 表 + * + * @param loginName 账号过滤条件,为空则初始化全部存量用户 + */ + @Log(title = "密评数据初始化", businessType = BusinessType.OTHER) + @PostMapping("/initSysUser") + public R> initSysUser(String loginName) { + if (loginName == null){ + loginName = "dumoulin392"; + } + return R.ok(cryptoSensitiveHsmService.initSysUserSensitiveData(loginName)); + } + +// /** +// * 初始化 sys_user 历史存量数据到 crypto_integrity_data 表 +// * +// * @param loginName 账号过滤条件,为空则初始化全部存量用户 +// */ +// @Log(title = "密评完整性摘要初始化", businessType = BusinessType.OTHER) +// @PostMapping("/initSysUserIntegrity") +// public R> initSysUserIntegrity(String loginName) { +// if (loginName == null){ +// loginName = "dumoulin392"; +// } +// return R.ok(cryptoSensitiveHsmService.initSysUserIntegrityData(loginName)); +// } +} diff --git a/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/ICryptoSensitiveHsmService.java b/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/ICryptoSensitiveHsmService.java index dee53a5d..8f7a484f 100644 --- a/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/ICryptoSensitiveHsmService.java +++ b/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/ICryptoSensitiveHsmService.java @@ -1,5 +1,7 @@ package org.dromara.system.service; +import java.util.Map; + /** * 密评敏感字段 HSM 加密服务 *

@@ -100,4 +102,35 @@ public interface ICryptoSensitiveHsmService { */ int verifyIntegrityHash(String tableName); + /** + * 初始化 sys_user 历史存量数据到 crypto_sensitive_data 表 + *

+ * 分页遍历 sys_user(del_flag='0')历史存量数据,对 password、phonenumber、certificateNumber + * 三个敏感字段做幂等初始化: + *

    + *
  • password:sys_user 中存储的 MD5 值直接作为待加密内容(口径与 SynUserInfoJob 一致)
  • + *
  • phonenumber / certificateNumber:纯数字等明文形态直接加密;AES 密文先解密为明文再 HSM 加密; + * 已是 HSM 密文或无法识别的数据跳过
  • + *
  • crypto_sensitive_data 中已存在活跃记录(tableName+bizId+fieldCode)的字段跳过,保证幂等可重复执行
  • + *
+ * + * @param userName 账号过滤条件,为空则初始化全部存量用户 + * @return 统计信息:total=扫描用户数、success=成功初始化字段数、skip=跳过字段数、fail=失败字段数 + */ + Map initSysUserSensitiveData(String loginName); + + /** + * 初始化 sys_user 历史存量数据到 crypto_integrity_data 表 + *

+ * 分页遍历 sys_user(del_flag='0')存量数据,对每个用户按 + * password、phonenumber、certificateNumber 三个字段(以 sys_user 当前存储值为准) + * 计算 HMAC-SM3 摘要,按 upsert 策略写入 crypto_integrity_data 表。 + * 已存在摘要记录的用户跳过,保证幂等可重复执行。 + * 摘要口径与 verifyIntegrityHash 校验链路(verifySysUserIntegrity)保持一致。 + * + * @param loginName 账号过滤条件,为空则初始化全部存量用户 + * @return 统计信息:total=扫描用户数、success=成功生成摘要数、skip=已有摘要跳过数、fail=失败数 + */ + Map initSysUserIntegrityData(String loginName); + } diff --git a/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/impl/CryptoSensitiveHsmServiceImpl.java b/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/impl/CryptoSensitiveHsmServiceImpl.java index dfcf86e3..e3b4f02e 100644 --- a/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/impl/CryptoSensitiveHsmServiceImpl.java +++ b/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/impl/CryptoSensitiveHsmServiceImpl.java @@ -3,6 +3,7 @@ package org.dromara.system.service.impl; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.HexUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -24,12 +25,16 @@ import org.dromara.system.mapper.SysOperLogMapper; import org.dromara.system.mapper.SysUserMapper; import org.dromara.system.service.ICryptoSensitiveHsmService; import org.dromara.system.service.IPasswordPartyService; +import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.nio.charset.StandardCharsets; import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; @Slf4j @RequiredArgsConstructor @@ -43,6 +48,9 @@ public class CryptoSensitiveHsmServiceImpl implements ICryptoSensitiveHsmService private final SysUserMapper sysUserMapper; private final SysOperLogMapper sysOperLogMapper; + @Value("${srnwg.secretKey}") + private String secretKey; + private static final String KEY_VERSION = "V1"; private static final String TABLE_SYS_USER = "sys_user"; private static final String TABLE_SYS_OPER_LOG = "sys_oper_log"; @@ -50,37 +58,42 @@ public class CryptoSensitiveHsmServiceImpl implements ICryptoSensitiveHsmService @Override @Transactional(rollbackFor = Exception.class) public String encryptAndSave(String tableName, String bizId, String fieldCode, String plainText) { - if (StrUtil.isBlank(plainText)) { - return null; - } - String inputHex = HexUtil.encodeHexStr(plainText.getBytes(StandardCharsets.UTF_8)); - SymmetryEncryptVo encryptResult = passwordPartyService.symmetryEncrypt(inputHex); + try{ + if (StrUtil.isBlank(plainText)) { + return null; + } + String inputHex = HexUtil.encodeHexStr(plainText.getBytes(StandardCharsets.UTF_8)); + SymmetryEncryptVo encryptResult = passwordPartyService.symmetryEncrypt(inputHex); - CryptoSensitiveData existing = queryActiveRecord(tableName, bizId, fieldCode); - if (existing != null) { - existing.setCipherText(encryptResult.getOutData()); - existing.setFieldIv(encryptResult.getIvData()); - existing.setFieldValue(plainText); - existing.setEncryptAlg("SM4-CBC"); - existing.setKeyVersion(KEY_VERSION); - cryptoSensitiveDataMapper.updateById(existing); - saveAuditRecord(tableName, bizId, fieldCode, existing.getId(), 3, "HSM SM4-CBC 加密更新"); - } else { - CryptoSensitiveData record = new CryptoSensitiveData(); - record.setTableName(tableName); - record.setBizId(bizId); - record.setFieldCode(fieldCode); - record.setFieldValue(plainText); - record.setCipherText(encryptResult.getOutData()); - record.setFieldIv(encryptResult.getIvData()); - record.setEncryptAlg("SM4-CBC"); - record.setKeyVersion(KEY_VERSION); - record.setIsActive(1); - record.setIsDeleted(0); - cryptoSensitiveDataMapper.insert(record); - saveAuditRecord(tableName, bizId, fieldCode, record.getId(), 1, "HSM SM4-CBC 加密存储"); + CryptoSensitiveData existing = queryActiveRecord(tableName, bizId, fieldCode); + if (existing != null) { + existing.setCipherText(encryptResult.getOutData()); + existing.setFieldIv(encryptResult.getIvData()); + existing.setFieldValue(plainText); + existing.setEncryptAlg("SM4-CBC"); + existing.setKeyVersion(KEY_VERSION); + cryptoSensitiveDataMapper.updateById(existing); + saveAuditRecord(tableName, bizId, fieldCode, existing.getId(), 3, "HSM SM4-CBC 加密更新"); + } else { + CryptoSensitiveData record = new CryptoSensitiveData(); + record.setTableName(tableName); + record.setBizId(bizId); + record.setFieldCode(fieldCode); + record.setFieldValue(plainText); + record.setCipherText(encryptResult.getOutData()); + record.setFieldIv(encryptResult.getIvData()); + record.setEncryptAlg("SM4-CBC"); + record.setKeyVersion(KEY_VERSION); + record.setIsActive(1); + record.setIsDeleted(0); + cryptoSensitiveDataMapper.insert(record); + saveAuditRecord(tableName, bizId, fieldCode, record.getId(), 1, "HSM SM4-CBC 加密存储"); + } + return encryptResult.getOutData(); + } catch (Exception e) { + log.error("HSM加密保存失败, tableName={}, bizId={}, fieldCode={}", tableName, bizId, fieldCode, e); } - return encryptResult.getOutData(); + return ""; } @Override @@ -123,77 +136,132 @@ public class CryptoSensitiveHsmServiceImpl implements ICryptoSensitiveHsmService @Override @Transactional(rollbackFor = Exception.class) public void saveIntegrityHash(String tableName, String bizId, String fieldList, String... plainValues) { - try{ - String hmacHash = calculateHash(fieldList, plainValues); - - LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); - lqw.eq(CryptoIntegrityData::getTableName, tableName) - .eq(CryptoIntegrityData::getBizId, bizId) - .eq(CryptoIntegrityData::getIsDeleted, 0); - CryptoIntegrityData existing = cryptoIntegrityDataMapper.selectOne(lqw); - - if (existing != null) { - existing.setFieldList(fieldList); - existing.setSm3Hash(hmacHash); - existing.setHashAlg("SM3"); - Date date = new Date(); - existing.setGenerateTime(date); - existing.setLastVerifyTime(date); - existing.setVerifyResult(1); - cryptoIntegrityDataMapper.updateById(existing); - } else { - CryptoIntegrityData record = new CryptoIntegrityData(); - record.setTableName(tableName); - record.setBizId(bizId); - record.setFieldList(fieldList); - record.setSm3Hash(hmacHash); - record.setHashAlg("SM3"); - Date date = new Date(); - record.setGenerateTime(date); - record.setLastVerifyTime(date); - record.setVerifyResult(1); - record.setIsDeleted(0); - cryptoIntegrityDataMapper.insert(record); - } + try { + doSaveIntegrityHash(tableName, bizId, fieldList, plainValues); } catch (Exception e) { log.error("保存数据完整性摘要失败, tableName={}, bizId={}", tableName, bizId, e); } } + /** + * 计算并 upsert 完整性摘要(异常向上抛出,供需要失败统计的调用方使用) + */ + private void doSaveIntegrityHash(String tableName, String bizId, String fieldList, String... plainValues) { + String hmacHash = calculateHash(fieldList, plainValues); + + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(CryptoIntegrityData::getTableName, tableName) + .eq(CryptoIntegrityData::getBizId, bizId) + .eq(CryptoIntegrityData::getIsDeleted, 0); + CryptoIntegrityData existing = cryptoIntegrityDataMapper.selectOne(lqw); + + if (existing != null) { + existing.setFieldList(fieldList); + existing.setSm3Hash(hmacHash); + existing.setHashAlg("SM3"); + Date date = new Date(); + existing.setGenerateTime(date); + existing.setLastVerifyTime(date); + existing.setVerifyResult(1); + cryptoIntegrityDataMapper.updateById(existing); + } else { + CryptoIntegrityData record = new CryptoIntegrityData(); + record.setTableName(tableName); + record.setBizId(bizId); + record.setFieldList(fieldList); + record.setSm3Hash(hmacHash); + record.setHashAlg("SM3"); + Date date = new Date(); + record.setGenerateTime(date); + record.setLastVerifyTime(date); + record.setVerifyResult(1); + record.setIsDeleted(0); + cryptoIntegrityDataMapper.insert(record); + } + } + + @Override public int verifyIntegrityHash(String tableName) { - if (!TABLE_SYS_USER.equals(tableName) && !TABLE_SYS_OPER_LOG.equals(tableName)) { - throw new ServiceException("暂不支持该业务表的完整性校验: " + tableName); + try{ + if (!TABLE_SYS_USER.equals(tableName) && !TABLE_SYS_OPER_LOG.equals(tableName)) { + throw new ServiceException("暂不支持该业务表的完整性校验: " + tableName); + } + Date today = DateUtil.beginOfDay(new Date()); + + int processed = 0; + int passed = 0; + int tampered = 0; + long pageSize = 500L; + Page page = new Page<>(1, pageSize); + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .eq(CryptoIntegrityData::getTableName, tableName) + .eq(CryptoIntegrityData::getIsDeleted, 0) + .lt(CryptoIntegrityData::getGenerateTime, today); + while (true) { + Page result = cryptoIntegrityDataMapper.selectPage(page, lqw); + for (CryptoIntegrityData record : result.getRecords()) { + try { + boolean matched = TABLE_SYS_USER.equals(tableName) + ? verifySysUserIntegrity(record) + : verifySysOperLogIntegrity(record); + record.setVerifyResult(matched ? 1 : 2); + record.setLastVerifyTime(new Date()); + cryptoIntegrityDataMapper.updateById(record); + processed++; + if (matched) { + passed++; + } else { + tampered++; + } + } catch (Exception e) { + log.warn("完整性校验失败, tableName={}, bizId={}", record.getTableName(), record.getBizId(), e); + } + } + if (!result.hasNext()) { + break; + } + page.setCurrent(page.getCurrent() + 1); + } + log.info("完整性校验完成, tableName={}, 处理={}, 通过={}, 异常={}", tableName, processed, passed, tampered); + return processed; + }catch (Exception e){ + log.error("数据完整性校验失败, tableName={}", tableName, e); } - Date today = DateUtil.beginOfDay(new Date()); + return 0; + } - int processed = 0; - int passed = 0; - int tampered = 0; + @Override + public Map initSysUserSensitiveData(String loginName) { + int total = 0, success = 0, skip = 0, fail = 0; long pageSize = 500L; - Page page = new Page<>(1, pageSize); - LambdaQueryWrapper lqw = new LambdaQueryWrapper() - .eq(CryptoIntegrityData::getTableName, tableName) - .eq(CryptoIntegrityData::getIsDeleted, 0) - .lt(CryptoIntegrityData::getGenerateTime, today); + Page page = new Page<>(1, pageSize); while (true) { - Page result = cryptoIntegrityDataMapper.selectPage(page, lqw); - for (CryptoIntegrityData record : result.getRecords()) { + Page result = DataPermissionHelper.ignore(() -> sysUserMapper.selectPage(page, + new LambdaQueryWrapper() + .eq(SysUser::getDelFlag, "0") + .eq(StrUtil.isNotBlank(loginName), SysUser::getLoginName, loginName))); + List records = result.getRecords(); + for (SysUser user : records) { + total++; + String bizId = String.valueOf(user.getUserId()); + // password:存储值(MD5)直接作为 HSM 加密输入,口径与 SynUserInfoJob 一致 + int r = initOneField(bizId, "password", user.getPassword(), "^[0-9a-f]{32}$", false); + if (r == 1) success++; else if (r == -1) fail++; else skip++; + // phonenumber / certificateNumber:存量已是 AES 密文,先 AES 加密(已有)再 HSM 加密 + r = initOneField(bizId, "phonenumber", user.getPhonenumber(), null, true); + if (r == 1) success++; else if (r == -1) fail++; else skip++; + r = initOneField(bizId, "certificateNumber", user.getCertificateNumber(), null, true); + if (r == 1) success++; else if (r == -1) fail++; else skip++; + try { - boolean matched = TABLE_SYS_USER.equals(tableName) - ? verifySysUserIntegrity(record) - : verifySysOperLogIntegrity(record); - record.setVerifyResult(matched ? 1 : 2); - record.setLastVerifyTime(new Date()); - cryptoIntegrityDataMapper.updateById(record); - processed++; - if (matched) { - passed++; - } else { - tampered++; - } + doSaveIntegrityHash(TABLE_SYS_USER, bizId, + "password,phonenumber,certificateNumber", + StrUtil.nullToEmpty(user.getPassword()), + StrUtil.nullToEmpty(user.getPhonenumber()), + StrUtil.nullToEmpty(user.getCertificateNumber())); } catch (Exception e) { - log.warn("完整性校验失败, tableName={}, bizId={}", record.getTableName(), record.getBizId(), e); + log.error("存量数据完整性摘要初始化失败, bizId={}", bizId, e); } } if (!result.hasNext()) { @@ -201,10 +269,17 @@ public class CryptoSensitiveHsmServiceImpl implements ICryptoSensitiveHsmService } page.setCurrent(page.getCurrent() + 1); } - log.info("完整性校验完成, tableName={}, 处理={}, 通过={}, 异常={}", tableName, processed, passed, tampered); - return processed; + log.info("sys_user 存量数据初始化完成: 扫描用户数={}, 成功字段数={}, 跳过字段数={}, 失败字段数={}", + total, success, skip, fail); + Map stats = new HashMap<>(); + stats.put("total", total); + stats.put("success", success); + stats.put("skip", skip); + stats.put("fail", fail); + return stats; } + @Override public int syncIntegrityHashModifiedUsers() { Date begin = DateUtil.beginOfDay(DateUtil.yesterday()); @@ -271,6 +346,112 @@ public class CryptoSensitiveHsmServiceImpl implements ICryptoSensitiveHsmService return processed; } + @Override + public Map initSysUserIntegrityData(String loginName) { + int total = 0, success = 0, skip = 0, fail = 0; + long pageSize = 500L; + Page page = new Page<>(1, pageSize); + while (true) { + Page result = DataPermissionHelper.ignore(() -> sysUserMapper.selectPage(page, + new LambdaQueryWrapper() + .eq(SysUser::getDelFlag, "0") + .eq(StrUtil.isNotBlank(loginName), SysUser::getLoginName, loginName))); + List records = result.getRecords(); + for (SysUser user : records) { + total++; + String bizId = String.valueOf(user.getUserId()); + if (existsIntegrityRecord(TABLE_SYS_USER, bizId)) { + skip++; + continue; + } + try { + doSaveIntegrityHash(TABLE_SYS_USER, bizId, + "password,phonenumber,certificateNumber", + StrUtil.nullToEmpty(user.getPassword()), + StrUtil.nullToEmpty(user.getPhonenumber()), + StrUtil.nullToEmpty(user.getCertificateNumber())); + success++; + } catch (Exception e) { + log.error("存量数据完整性摘要初始化失败, bizId={}", bizId, e); + fail++; + } + } + if (!result.hasNext()) { + break; + } + page.setCurrent(page.getCurrent() + 1); + } + log.info("sys_user 存量完整性摘要初始化完成: 扫描用户数={}, 成功={}, 跳过={}, 失败={}", + total, success, skip, fail); + Map stats = new HashMap<>(); + stats.put("total", total); + stats.put("success", success); + stats.put("skip", skip); + stats.put("fail", fail); + return stats; + } + + /** + * 查询指定业务记录是否已存在完整性摘要 + */ + private boolean existsIntegrityRecord(String tableName, String bizId) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(CryptoIntegrityData::getTableName, tableName) + .eq(CryptoIntegrityData::getBizId, bizId) + .eq(CryptoIntegrityData::getIsDeleted, 0); + return cryptoIntegrityDataMapper.selectCount(lqw) > 0; + } + + /** + * 初始化单个敏感字段(幂等) + * + * @param plainPattern 明文形态兜底正则(aesCipherInput=false 时使用) + * @param aesCipherInput true=存储值为 AES 密文,AES 密文直接作为 HSM 加密输入(先 AES 后 HSM) + * @return 1=成功、0=跳过、-1=失败 + */ + private int initOneField(String bizId, String fieldCode, String storedValue, + String plainPattern, boolean aesCipherInput) { + if (StrUtil.isBlank(storedValue)) { + return 0; + } + if (queryActiveRecord(TABLE_SYS_USER, bizId, fieldCode) != null) { + return 0; + } + String hsmInput; + if (aesCipherInput) { + // 双加密规则:明文 → AES 加密 → HSM 加密。 + // 存量即为 AES 密文,AES 解密仅用于形态判定,解密成功则原值直接作为 HSM 输入 + if (!isAesCipherText(storedValue)) { + log.warn("存量字段非AES密文形态, 跳过初始化, bizId={}, fieldCode={}", bizId, fieldCode); + return 0; + } + hsmInput = storedValue; + } else { + hsmInput = (plainPattern != null && storedValue.matches(plainPattern)) ? storedValue : null; + if (hsmInput == null) { + return 0; + } + } + try { + encryptAndSave(TABLE_SYS_USER, bizId, fieldCode, hsmInput); + return 1; + } catch (Exception e) { + log.error("存量数据初始化失败, bizId={}, fieldCode={}", bizId, fieldCode, e); + return -1; + } + } + + /** + * 判断存储值是否为 AES 密文形态(用 srnwg.secretKey 尝试解密,成功即可解密) + */ + private boolean isAesCipherText(String value) { + try { + return StrUtil.isNotBlank(SecureUtil.aes(SecureUtil.decode(secretKey)).decryptStr(value)); + } catch (Exception ignored) { + return false; + } + } + private CryptoSensitiveData queryActiveRecord(String tableName, String bizId, String fieldCode) { LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); lqw.eq(CryptoSensitiveData::getTableName, tableName) diff --git a/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/impl/PasswordPartyServiceImpl.java b/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/impl/PasswordPartyServiceImpl.java index 983e1ee8..3f0402df 100644 --- a/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/impl/PasswordPartyServiceImpl.java +++ b/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/service/impl/PasswordPartyServiceImpl.java @@ -49,6 +49,10 @@ public class PasswordPartyServiceImpl implements IPasswordPartyService { */ @Override public SymmetryEncryptVo symmetryEncrypt(String inputData) { +// SymmetryEncryptVo symmetryEncryptVo = new SymmetryEncryptVo(); +// symmetryEncryptVo.setIvData("1234567890123456"); +// symmetryEncryptVo.setOutData("123"); +// return symmetryEncryptVo; // TODO 生成随机数,目前使用SecureRandom,后续需要替换为HSM生成随机数 String iv = generateRandom(16); // SecureRandom secureRandom = new SecureRandom(); diff --git a/zdxt-web-server/zdxt-admin-web-server/src/main/resources/businessdatasyn/sys_user.json b/zdxt-web-server/zdxt-admin-web-server/src/main/resources/businessdatasyn/sys_user.json index b2e5103d..bfc534ab 100644 --- a/zdxt-web-server/zdxt-admin-web-server/src/main/resources/businessdatasyn/sys_user.json +++ b/zdxt-web-server/zdxt-admin-web-server/src/main/resources/businessdatasyn/sys_user.json @@ -1,7 +1,7 @@ { "configKey": "sys_user", "description": "用户表双向同步", - "enabled": true, + "enabled": false, "v1": { "table": "sys_user",