6 changed files with 272 additions and 5 deletions
@ -0,0 +1,28 @@ |
|||||
|
package com.zdxt.enforcementcode.quartz.job; |
||||
|
|
||||
|
import com.zdxt.enforcementcode.service.ICryptoService; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
/** |
||||
|
* 密码平台 |
||||
|
* <p>行政执法检查数据一致性校验</p> |
||||
|
* |
||||
|
* @author zrb |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Component |
||||
|
@RequiredArgsConstructor |
||||
|
public class CryptoSensitiveOperXzzfJob { |
||||
|
private final ICryptoService cryptoService; |
||||
|
public void execute(){ |
||||
|
this.verifyXzzfInfo(); |
||||
|
} |
||||
|
|
||||
|
public void verifyXzzfInfo(){ |
||||
|
log.info("行政执法检查数据一致性校验开始"); |
||||
|
cryptoService.verifyXzzfInfo(); |
||||
|
log.info("行政执法检查数据一致性校验结束"); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
package com.zdxt.enforcementcode.service; |
||||
|
|
||||
|
import org.dromara.common.mybatis.core.page.PageQuery; |
||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo; |
||||
|
|
||||
|
import java.util.Collection; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 密码服务 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2026-05-25 |
||||
|
*/ |
||||
|
public interface ICryptoService { |
||||
|
|
||||
|
/** |
||||
|
* 同步前一天有变更的执法登记(enforcement_registration)数据完整性摘要 |
||||
|
* <p> |
||||
|
* 查询 update_time 落在前一天范围内的记录(is_delete=0),以数据库中实际存储值 |
||||
|
* (enterprise_id、law_enforcer_id、law_enforcement_item_text)计算 HMAC-SM3 摘要, |
||||
|
* 按 upsert 策略写入 crypto_integrity_data 表,供后续完整性校验比对。 |
||||
|
* |
||||
|
* @return 成功处理的记录数 |
||||
|
*/ |
||||
|
int syncIntegrityHashXzzf(); |
||||
|
|
||||
|
/** |
||||
|
* 校验执法登记(enforcement_registration)数据完整性摘要 |
||||
|
* <p> |
||||
|
* 查询 crypto_integrity_data 中 table_name=enforcement_registration 且 generate_time 早于今天的 |
||||
|
* 基准摘要记录,回查业务表当前数据重算摘要并比对: |
||||
|
* 一致标记 verify_result=1(通过),不一致标记 verify_result=2(篡改), |
||||
|
* 校验异常标记 verify_result=4(校验异常, 非篡改),数据不存在或已删除标记 verify_result=3(跳过), |
||||
|
* 同时刷新 last_verify_time。 |
||||
|
* |
||||
|
* @return 完成校验的记录数 |
||||
|
*/ |
||||
|
int verifyXzzfInfo(); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,158 @@ |
|||||
|
package com.zdxt.enforcementcode.service.impl; |
||||
|
|
||||
|
import cn.hutool.core.date.DateUtil; |
||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
|
import com.zdxt.enforcementcode.domain.EnforcementRegistration; |
||||
|
import com.zdxt.enforcementcode.mapper.EnforcementRegistrationMapper; |
||||
|
import com.zdxt.enforcementcode.service.ICryptoService; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.dromara.common.core.exception.ServiceException; |
||||
|
import org.dromara.common.core.utils.StringUtils; |
||||
|
import org.dromara.common.mybatis.helper.DataPermissionHelper; |
||||
|
import org.dromara.system.domain.bean.CryptoIntegrityData; |
||||
|
import org.dromara.system.mapper.CryptoIntegrityDataMapper; |
||||
|
import org.dromara.system.service.ICryptoSensitiveHsmService; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* 新增密码服务实现 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@RequiredArgsConstructor |
||||
|
@Service |
||||
|
public class CryptoServiceServiceImpl implements ICryptoService { |
||||
|
|
||||
|
private final ICryptoSensitiveHsmService cryptoSensitiveHsmService; |
||||
|
private final EnforcementRegistrationMapper enforcementRegistrationMapper; |
||||
|
private final CryptoIntegrityDataMapper cryptoIntegrityDataMapper; |
||||
|
|
||||
|
private static final String TABLE_ENFORCEMENT_REGISTRATION = "enforcement_registration"; |
||||
|
|
||||
|
/** |
||||
|
* 摘要字段口径: 使用数据库列名, 与 sys_oper_log 基线风格一致 |
||||
|
*/ |
||||
|
private static final String ER_FIELD_LIST = "enterprise_id,law_enforcer_id,law_enforcement_item_text"; |
||||
|
|
||||
|
@Override |
||||
|
public int syncIntegrityHashXzzf() { |
||||
|
Date begin = DateUtil.beginOfDay(DateUtil.yesterday()); |
||||
|
Date end = DateUtil.endOfDay(DateUtil.yesterday()); |
||||
|
|
||||
|
int processed = 0; |
||||
|
long pageSize = 500L; |
||||
|
Page<EnforcementRegistration> page = new Page<>(1, pageSize); |
||||
|
while (true) { |
||||
|
Page<EnforcementRegistration> result = DataPermissionHelper.ignore(() -> |
||||
|
enforcementRegistrationMapper.selectPage(page, new LambdaQueryWrapper<EnforcementRegistration>() |
||||
|
.select(EnforcementRegistration::getId, EnforcementRegistration::getEnterpriseId, |
||||
|
EnforcementRegistration::getLawEnforcerId, EnforcementRegistration::getLawEnforcementItemText) |
||||
|
.eq(EnforcementRegistration::getIsDelete, 0) |
||||
|
.eq(EnforcementRegistration::getIsSubmit, 1) |
||||
|
.ge(EnforcementRegistration::getUpdateTime, begin) |
||||
|
.le(EnforcementRegistration::getUpdateTime, end) |
||||
|
.orderByAsc(EnforcementRegistration::getId))); |
||||
|
for (EnforcementRegistration er : result.getRecords()) { |
||||
|
try { |
||||
|
cryptoSensitiveHsmService.saveIntegrityHash(TABLE_ENFORCEMENT_REGISTRATION, er.getId(), ER_FIELD_LIST, |
||||
|
StringUtils.isNotBlank(er.getEnterpriseId()) ? er.getEnterpriseId() : "", |
||||
|
StringUtils.isNotBlank(er.getLawEnforcerId()) ? er.getLawEnforcerId() : "", |
||||
|
StringUtils.isNotBlank(er.getLawEnforcementItemText()) ? er.getLawEnforcementItemText() : ""); |
||||
|
processed++; |
||||
|
} catch (Exception e) { |
||||
|
log.warn("同步前一天修改执法登记完整性摘要失败, id={}", er.getId(), e); |
||||
|
} |
||||
|
} |
||||
|
if (!result.hasNext()) { |
||||
|
break; |
||||
|
} |
||||
|
page.setCurrent(page.getCurrent() + 1); |
||||
|
} |
||||
|
log.info("同步前一天修改执法登记完整性摘要完成, 处理数量={}", processed); |
||||
|
return processed; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public int verifyXzzfInfo() { |
||||
|
Date today = DateUtil.beginOfDay(new Date()); |
||||
|
|
||||
|
int processed = 0, passed = 0, tampered = 0, skipped = 0, errored = 0; |
||||
|
long pageSize = 500L; |
||||
|
Page<CryptoIntegrityData> page = new Page<>(1, pageSize); |
||||
|
LambdaQueryWrapper<CryptoIntegrityData> lqw = new LambdaQueryWrapper<CryptoIntegrityData>() |
||||
|
.eq(CryptoIntegrityData::getTableName, TABLE_ENFORCEMENT_REGISTRATION) |
||||
|
.eq(CryptoIntegrityData::getIsDeleted, 0) |
||||
|
.lt(CryptoIntegrityData::getGenerateTime, today); |
||||
|
while (true) { |
||||
|
Page<CryptoIntegrityData> result = DataPermissionHelper.ignore( |
||||
|
() -> cryptoIntegrityDataMapper.selectPage(page, lqw)); |
||||
|
for (CryptoIntegrityData record : result.getRecords()) { |
||||
|
try { |
||||
|
EnforcementRegistration er = DataPermissionHelper.ignore( |
||||
|
() -> enforcementRegistrationMapper.selectById(record.getBizId())); |
||||
|
if (er == null || (er.getIsDelete() != null && er.getIsDelete() == 1)) { |
||||
|
record.setVerifyResult(3); |
||||
|
skipped++; |
||||
|
} else { |
||||
|
String currentHash = cryptoSensitiveHsmService.computeIntegrityHash( |
||||
|
record.getFieldList(), resolveValues(record.getFieldList(), er)); |
||||
|
if (currentHash.equals(record.getSm3Hash())) { |
||||
|
record.setVerifyResult(1); |
||||
|
passed++; |
||||
|
} else { |
||||
|
record.setVerifyResult(2); |
||||
|
tampered++; |
||||
|
log.error("执法登记完整性校验未通过, 疑似篡改, id={}, fieldList={}", |
||||
|
record.getBizId(), record.getFieldList()); |
||||
|
} |
||||
|
} |
||||
|
record.setLastVerifyTime(new Date()); |
||||
|
cryptoIntegrityDataMapper.updateById(record); |
||||
|
processed++; |
||||
|
} catch (Exception e) { |
||||
|
// 校验异常(如 fieldList 声明不支持字段): 状态 4, 与篡改(2)区分
|
||||
|
log.error("执法登记完整性校验异常, id={}", record.getBizId(), e); |
||||
|
record.setVerifyResult(4); |
||||
|
record.setLastVerifyTime(new Date()); |
||||
|
cryptoIntegrityDataMapper.updateById(record); |
||||
|
errored++; |
||||
|
processed++; |
||||
|
} |
||||
|
} |
||||
|
if (!result.hasNext()) { |
||||
|
break; |
||||
|
} |
||||
|
page.setCurrent(page.getCurrent() + 1); |
||||
|
} |
||||
|
if (tampered > 0) { |
||||
|
log.error("执法登记完整性校验发现疑似篡改记录, 数量={}(须人工核查, 基线已锁定拒绝自动覆盖)", tampered); |
||||
|
} |
||||
|
if (errored > 0) { |
||||
|
log.warn("执法登记完整性校验存在校验异常记录, 数量={}(程序缺陷或脏数据, 须排查代码, 非篡改)", errored); |
||||
|
} |
||||
|
log.info("执法登记完整性校验完成, 处理={}, 通过={}, 篡改={}, 校验异常={}, 跳过(数据不存在)={}", |
||||
|
processed, passed, tampered, errored, skipped); |
||||
|
return processed; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 按基线 fieldList 声明解析当前库中字段值(顺序与 fieldList 严格对应) |
||||
|
*/ |
||||
|
private String[] resolveValues(String fieldList, EnforcementRegistration er) { |
||||
|
String[] fields = fieldList.split(","); |
||||
|
String[] values = new String[fields.length]; |
||||
|
for (int i = 0; i < fields.length; i++) { |
||||
|
String field = fields[i].trim(); |
||||
|
switch (field) { |
||||
|
case "enterprise_id" -> values[i] = er.getEnterpriseId() != null ? er.getEnterpriseId() : ""; |
||||
|
case "law_enforcer_id" -> values[i] = er.getLawEnforcerId() != null ? er.getLawEnforcerId() : ""; |
||||
|
case "law_enforcement_item_text" -> values[i] = er.getLawEnforcementItemText() != null ? er.getLawEnforcementItemText() : ""; |
||||
|
default -> throw new ServiceException("不支持的执法登记完整性校验字段: " + field); |
||||
|
} |
||||
|
} |
||||
|
return values; |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue