package com.yau.digitalrmb.institutionidentity.application; import com.yau.digitalrmb.institutionidentity.domain.InstitutionIdentifierApplication; import com.yau.digitalrmb.institutionidentity.domain.InstitutionIdentifierRepository; import com.yau.digitalrmb.institutionidentity.domain.InstitutionIdentityCryptography; import com.yau.digitalrmb.shared.api.ErrorCode; import com.yau.digitalrmb.shared.exception.BusinessException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; @Service public class InstitutionApplicationVerificationService { @Resource private InstitutionIdentityCryptography cryptography; @Resource private InstitutionKeyService keyService; @Resource private InstitutionIdentifierRepository repository; @Resource private InstitutionTrainingErrorRecorder errorRecorder; @Transactional public InstitutionApplicationVerificationResult verify(long applicationId, String verificationKeyId, InstitutionKeySubject subject, String operator) { InstitutionIdentifierApplication application = requireApplication(applicationId); if (!InstitutionKeyService.BANK_SECOND_KEY.equals(verificationKeyId)) { recordAndThrow(application, "WRONG_KEY", "VERIFY", verificationKeyId, "验证必须选择商业银行第二密钥的公钥", operator); } requireStatus(application, InstitutionIdentifierApplication.Status.PACKAGED, "当前步骤不是央行验证,不能操作", operator); InstitutionIdentifierApplication.Status expectedStatus = application.getStatus(); String originalText = application.getBankCode() + "|" + application.getTimestamp(); String recalculatedDigest = cryptography.sm3(originalText); boolean signatureValid = keyService.verifyCommercialBank(subject, application.getDigest(), application.getBankSignature()); boolean digestMatches = recalculatedDigest.equalsIgnoreCase(application.getDigest()); invokeDomain(() -> application.recordVerification(verificationKeyId, signatureValid, digestMatches)); repository.update(application, expectedStatus, "VERIFY", signatureValid && digestMatches ? "SM2身份验证和SM3完整性验证通过" : "申请验证失败", operator); return new InstitutionApplicationVerificationResult(applicationId, application.getStatus().name(), "SM2_WITH_SM3_VERIFY_AND_SM3_RECALCULATE", verificationKeyId, originalText, application.getDigest(), recalculatedDigest, signatureValid, digestMatches); } @Transactional public InstitutionIdentifierConfirmationResult confirm(long applicationId, String signingKeyId, InstitutionKeySubject subject, String operator) { InstitutionIdentifierApplication application = requireApplication(applicationId); if (!InstitutionKeyService.CENTRAL_FIRST_KEY.equals(signingKeyId)) { recordAndThrow(application, "WRONG_KEY", "CONFIRM", signingKeyId, "签名确权必须选择中央银行第一密钥", operator); } requireStatus(application, InstitutionIdentifierApplication.Status.VERIFIED, "申请尚未验证通过,不能进行央行签名确权", operator); InstitutionIdentifierApplication.Status expectedStatus = application.getStatus(); String digest = application.getDigest(); String identifier = "ORG_" + digest.substring(0, 12); String centralBankSignature = keyService.signCentralBank(subject, digest); invokeDomain(() -> application.issue(signingKeyId, identifier, centralBankSignature)); repository.update(application, expectedStatus, "CONFIRM", "中央银行第一私钥完成SM2签名确权并签发机构标识", operator); return new InstitutionIdentifierConfirmationResult(applicationId, application.getStatus().name(), signingKeyId, centralBankSignature, identifier, digest); } private InstitutionIdentifierApplication requireApplication(long applicationId) { return repository.findById(applicationId).orElseThrow(() -> new BusinessException(ErrorCode.RESOURCE_NOT_FOUND, "机构标识申请不存在")); } private void requireStatus(InstitutionIdentifierApplication application, InstitutionIdentifierApplication.Status expectedStatus, String message, String operator) { if (application.getStatus() != expectedStatus) { recordAndThrow(application, "INVALID_STEP", expectedStatus.name(), null, message + ",当前状态:" + application.getStatus().name(), operator); } } private void recordAndThrow(InstitutionIdentifierApplication application, String errorType, String operationStep, String providedKeyId, String message, String operator) { int errorSequence = errorRecorder.record(application.getId(), errorType, operationStep, providedKeyId, message, operator); throw new BusinessException(ErrorCode.VALIDATION_ERROR, message + ",本次实训第" + errorSequence + "次错误"); } private static void invokeDomain(Runnable operation) { try { operation.run(); } catch (IllegalArgumentException | IllegalStateException exception) { throw new BusinessException(ErrorCode.VALIDATION_ERROR, exception.getMessage()); } } }