====== 모바일 운전면허증 ====== ===== 개요 ===== - 모바일 신분증은 개인 스마트폰에 안전하게 저장하여 편리하게 사용할 수 있는 신분증으로 신분증이 필요한 모든 곳에서 편리하게 사용할 수 있다. - 개인이 스마트폰 안에 자신의 정보를 보유하고 직접 꺼내 쓰며, 신원 증명을 위해 필요한 정보만 골라서 제공할 수 있어 자기 정보 결정권이 강화된다. - 내 신원 정보는 내 스마트폰 안에만 안전하게 보관되며, 블록체인을 통해 신원 정보의 진위 여부를 확인할 수 있다. - 모바일 신분증 하나로 오프라인과 온라인에서 간편하고 안전하게 사용할 수 있다. - 모바일 운전면허증은 한국조폐공사장으로 연계 서비스 신청서 공문을 접수하여 심의 승인 후 연계 서비스를 개발한다. * 모바일 신분증 홈페이지 [[https://www.mobileid.go.kr/mip/hps/main.do|https://www.mobileid.go.kr/mip/hps/main.do]] * 모바일 신분증 개발지원센터 [[https://dev.mobileid.go.kr/mip/dfs/dfsmain.do|https://dev.mobileid.go.kr/mip/dfs/dfsmain.do]] - 표준프레임워크는 연계모듈을 이용한 애플리케이션 개발에 활용할 수 있는 예제를 제공한다. ===== 연계서비스 이용절차 ===== - 모바일 신분증 개발지원센터에서 모바일 신분증 연계신청서 다운로드 및 작성. * 모바일 신분증 연계 안내페이지 [[https://dev.mobileid.go.kr/mip/dfs/apiuse/apiusestep.do|https://dev.mobileid.go.kr/mip/dfs/apiuse/apiusestep.do]] - 수신처 한국조폐공사장으로 공문 접수. - 심의 결과에 따른 승인/보완/반려 처리. - 승인 후 연계서비스 개발. ===== 설명 ===== ==== 관련소스 ==== ^유형^대상소스명^비고^ |DAO|java.egovframework.com.sec.rnc.mip.mva.sp.comm.dao.SvcDAO.java|서비스 처리| |DAO|java.egovframework.com.sec.rnc.mip.mva.sp.comm.dao.TrxInfoDAO.java|거래 처리| |Enum|java.egovframework.com.sec.rnc.mip.mva.sp.comm.enums.AuthTypeEnum.java|상수 집합| |Enum|java.egovframework.com.sec.rnc.mip.mva.sp.comm.enums.MipErrorEnum.java|상수 집합| |Enum|java.egovframework.com.sec.rnc.mip.mva.sp.comm.enums.ModeEnum.java|상수 집합| |Enum|java.egovframework.com.sec.rnc.mip.mva.sp.comm.enums.PresentTypeEnum.java|상수 집합| |Enum|java.egovframework.com.sec.rnc.mip.mva.sp.comm.enums.RequestTypeEnum.java|상수 집합| |Enum|java.egovframework.com.sec.rnc.mip.mva.sp.comm.enums.TrxStsCodeEnum.java|상수 집합| |Enum|java.egovframework.com.sec.rnc.mip.mva.sp.comm.enums.VcStatusEnum.java|상수 집합| |Exception|java.egovframework.com.sec.rnc.mip.mva.sp.comm.exception.SpException.java|예외 처리| |Exception|java.egovframework.com.sec.rnc.mip.mva.sp.comm.exception.SpExceptionHandler.java|예외 처리| |Service|java.egovframework.com.sec.rnc.mip.mva.sp.comm.service.DirectService.java|다이렉트 모드 처리| |Service|java.egovframework.com.sec.rnc.mip.mva.sp.comm.service.MipDidVpService.java|DID 검증 처리| |Service|java.egovframework.com.sec.rnc.mip.mva.sp.comm.service.MipProperties.java|프로퍼티 처리| |Service|java.egovframework.com.sec.rnc.mip.mva.sp.comm.service.SvcService.java|서비스 처리| |Service|java.egovframework.com.sec.rnc.mip.mva.sp.comm.service.TrxInfoService.java|거래 처리| |ServiceImpl|java.egovframework.com.sec.rnc.mip.mva.sp.comm.service.impl.DirectServiceImpl.java|다이렉트 모드 처리| |ServiceImpl|java.egovframework.com.sec.rnc.mip.mva.sp.comm.service.impl.MipDidVpServiceImpl.java|DID 검증 처리| |ServiceImpl|java.egovframework.com.sec.rnc.mip.mva.sp.comm.service.impl.SvcServiceImpl.java|서비스 처리| |ServiceImpl|java.egovframework.com.sec.rnc.mip.mva.sp.comm.service.impl.TrxInfoServiceImpl.java|거래 처리| |Util|java.egovframework.com.sec.rnc.mip.mva.sp.comm.util.Base64Util.java|Base64 유틸| |Util|java.egovframework.com.sec.rnc.mip.mva.sp.comm.util.Generator.java|Generator 유틸| |VO|java.egovframework.com.sec.rnc.mip.mva.sp.comm.vo.M200VO.java|VP 요청 메시지 VO| |VO|java.egovframework.com.sec.rnc.mip.mva.sp.comm.vo.M310VO.java|Profile 요청 메시지 VO| |VO|java.egovframework.com.sec.rnc.mip.mva.sp.comm.vo.M400VO.java|VP 제출 메시지 VO| |VO|java.egovframework.com.sec.rnc.mip.mva.sp.comm.vo.M900VO.java|오류 메시지 VO| |VO|java.egovframework.com.sec.rnc.mip.mva.sp.comm.vo.MipApiDataVO.java|검증 API 데이터 VO| |VO|java.egovframework.com.sec.rnc.mip.mva.sp.comm.vo.SvcVO.java|검증 서비스 VO| |VO|java.egovframework.com.sec.rnc.mip.mva.sp.comm.vo.T510VO.java|QR-MPM 시작용 VO| |VO|java.egovframework.com.sec.rnc.mip.mva.sp.comm.vo.TrxInfoSvcVO.java|거래 & 서비스 정보 VO| |VO|java.egovframework.com.sec.rnc.mip.mva.sp.comm.vo.TrxInfoVO.java|거래 정보 VO| |VO|java.egovframework.com.sec.rnc.mip.mva.sp.comm.vo.VP.java|VP 정보 VO| |Controller|java.egovframework.com.sec.rnc.mip.mva.sp.comm.web.MipController.java|MIP 검증 처리| |Config|java.egovframework.com.sec.rnc.mip.mva.sp.config.ConfigBean.java|환경 설정 파일| |Service|java.egovframework.com.sec.rnc.mip.mva.sp.qrmpm.service.QrmpmService.java|QR-MPM 인터페이스 검증 처리| |ServiceImpl|java.egovframework.com.sec.rnc.mip.mva.sp.qrmpm.service.impl.QrmpmServiceImpl.java|QR-MPM 인터페이스 검증 처리| |Controller|java.egovframework.com.sec.rnc.mip.mva.sp.qrmpm.web.QrmpmController.java|QR-MPM 인터페이스 검증 처리| |Controller|java.egovframework.com.sec.rnc.mip.mva.sp.qrmpm.web.QrmpmViewController.java|QR-MPM 화면 이동| |XML|resources/egovframework/mapper/com/sec/rnc/mip/SERVICE_SQL_altibase.xml|서비스 처리 Altibase Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/SERVICE_SQL_cubrid.xml|서비스 처리 Cubrid Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/SERVICE_SQL_goldilocks.xml|서비스 처리 Goldilocks Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/SERVICE_SQL_maria.xml|서비스 처리 Maria Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/SERVICE_SQL_mysql.xml|서비스 처리 Mysql Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/SERVICE_SQL_oracle.xml|서비스 처리 Oracle Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/SERVICE_SQL_postgres.xml|서비스 처리 Postgres Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/SERVICE_SQL_tibero.xml|서비스 처리 Tibero Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/TRX_INFO_SQL_altibase.xml|거래 처리 Altibase Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/TRX_INFO_SQL_cubrid.xml|거래 처리 Cubrid Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/TRX_INFO_SQL_goldilocks.xml|거래 처리 Goldilocks Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/TRX_INFO_SQL_maria.xml|거래 처리 Maria Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/TRX_INFO_SQL_mysql.xml|거래 처리 Mysql Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/TRX_INFO_SQL_oracle.xml|거래 처리 Oracle Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/TRX_INFO_SQL_postgres.xml|거래 처리 Postgres Mapper| |XML|resources/egovframework/mapper/com/sec/rnc/mip/TRX_INFO_SQL_tibero.xml|거래 처리 Tibero Mapper| |Property|resources/egovframework/message/com/cmm/message-common_en.properties|메시지 처리| |Property|resources/egovframework/message/com/cmm/message-common_ko.properties|메시지 처리| |연계용 환경설정|resources/egovframework/mip/mip.properties|환경 설정 파일| |연계용 모듈|resources/egovframework/mip/sp.did|개인 식별 문서| |연계용 모듈|resources/egovframework/mip/sp.wallet|개인 식별 키를 담은 암호화 지갑| |SCRIPT|script/comment/altibase/egov_altibase_comment.sql|Altibase 코멘트 Script| |SCRIPT|script/comment/cubrid/egov_cubrid_comment.sql|Cubrid 코멘트 Script| |SCRIPT|script/comment/goldilocks/egov_goldilocks_comment.sql|Goldilocks 코멘트 Script| |SCRIPT|script/comment/maria/egov_maria_comment.sql|Maria 코멘트 Script| |SCRIPT|script/comment/mysql/egov_mysql_comment.sql|Mysql 코멘트 Script| |SCRIPT|script/comment/oracle/egov_oracle_comment.sql|Oracle 코멘트 Script| |SCRIPT|script/comment/postgres/egov_postgres_comment.sql|Postgres 코멘트 Script| |SCRIPT|script/comment/tibero/egov_tibero_comment.sql|Tibero 코멘트 Script| |SCRIPT|script/ddl/altibase/com_DDL_altibase.sql|Altibase DDL Script| |SCRIPT|script/ddl/cubrid/com_DDL_cubrid.sql|Cubrid DDL Script| |SCRIPT|script/ddl/goldilocks/com_DDL_goldilocks.sql|Goldilocks DDL Script| |SCRIPT|script/ddl/maria/com_DDL_maria.sql|Maria DDL Script| |SCRIPT|script/ddl/mysql/com_DDL_mysql.sql|Mysql DDL Script| |SCRIPT|script/ddl/oracle/com_DDL_oracle.sql|Oracle DDL Script| |SCRIPT|script/ddl/postgres/com_DDL_postgres.sql|Postgres DDL Script| |SCRIPT|script/ddl/tibero/com_DDL_tibero.sql|Tibero DDL Script| |SCRIPT|script/dml/altibase/com_DML_altibase.sql|Altibase DML Script| |SCRIPT|script/dml/cubrid/com_DML_cubrid.sql|Cubrid DML Script| |SCRIPT|script/dml/goldilocks/com_DML_goldilocks.sql|Goldilocks DML Script| |SCRIPT|script/dml/maria/com_DML_maria.sql|Maria DML Script| |SCRIPT|script/dml/mysql/com_DML_mysql.sql|Mysql DML Script| |SCRIPT|script/dml/oracle/com_DML_oracle.sql|Oracle DML Script| |SCRIPT|script/dml/postgres/com_DML_postgres.sql|Postgres DML Script| |SCRIPT|script/dml/tibero/com_DML_tibero.sql|Tibero DML Script| |CSS|webapp/css/egovframework/com/sec/rnc/mip/common.css|공통 css| |CSS|webapp/css/egovframework/com/sec/rnc/mip/style.css|디자인 css| |Image|webapp/images/egovframework/com/sec/rnc/mip/bg/bg-select.svg|화면 구성 이미지 파일| |Image|webapp/images/egovframework/com/sec/rnc/mip/bg/sample-qrcode.png|화면 구성 이미지 파일| |Image|webapp/images/egovframework/com/sec/rnc/mip/icon/ic-calendar.svg|화면 구성 이미지 파일| |Image|webapp/images/egovframework/com/sec/rnc/mip/icon/ic-sub-tit.svg|화면 구성 이미지 파일| |JS|webapp/js/egovframework/com/sec/rnc/mip/comm/base64.min.js|Base64 js| |JS|webapp/js/egovframework/com/sec/rnc/mip/comm/common.js|공통 js| |JS|webapp/js/egovframework/com/sec/rnc/mip/comm/jquery-3.6.0.js|jQuery js| |JS|webapp/js/egovframework/com/sec/rnc/mip/comm/jsQR.js|QR js| |JS|webapp/js/egovframework/com/sec/rnc/mip/comm/qrcode.js|QR js| |JS|webapp/js/egovframework/com/sec/rnc/mip/qrmpm.js|QR-MPM 화면 js| |DispatcherServlet|webapp/WEB-INF/config/egovframework/springmvc/egov-com-servlet.xml|json 맵핑용 Message Converter Bean 추가| |JSP|webapp/WEB-INF/jsp/egovframework/com/sec/rnc/mip/comm/header.jsp|css, js 추가| |JSP|webapp/WEB-INF/jsp/egovframework/com/sec/rnc/mip/comm/trxsts.jsp|거래 처리 화면| |JSP|webapp/WEB-INF/jsp/egovframework/com/sec/rnc/mip/qrmpm/qrmpmView.jsp|QR-MPM 검증 화면| |연계용 모듈|webapp/WEB-INF/lib/OmniEnt-SDK-Core-v1.0.3.5-nolicensecheck.jar|모바일 운전면허증 라이브러리| |연계용 모듈|webapp/WEB-INF/lib/OmniEnt-SDK-ServerCore-v1.0.3.5.jar|모바일 운전면허증 라이브러리| |연계용 모듈|webapp/WEB-INF/lib/OmniEnt-SDK-Verifier-v1.0.3.6.jar|모바일 운전면허증 라이브러리| |연계용 모듈|webapp/WEB-INF/lib/RSLicenseSDK_jdk16_1.0.4.jar|모바일 운전면허증 라이브러리| |연계용 환경설정|pom.xml|모바일 운전면허증 라이브러리 및 Util Dependency 추가| ==== 관련테이블 ==== ^테이블명^테이블명(영문)^비고^ |SP 서비스|COMTCMOBILEIDSERVICE|SP 서비스 정보를 관리한다.| |SP 거래정보|COMTSMOBILEIDTRXINFO|SP 거래 정보를 관리한다.| ==== 환경설정 ==== - 위키가이드의 [[egovframework:dev4.1:imp:editor:common_component|공통컴포넌트 시작하기]]를 참고하여 공통컴포넌트를 설치한다. - 모바일 운전면허증 서비스 신청 승인 후 생성한 DID Document 및 Wallet 파일을 공통컴포넌트 프로젝트에 추가한다. * 추가할 위치는 위의 관련소스 부분을 참고한다. - mip.properties 파일에 개발환경에 맞게 환경설정한다. ################################################################################# # Server Settings ################################################################################# # blockchain node address : 블록체인 노드 주소(모바일 운전면허증에서 제공) app.blockchain-server-domain=https://bcdev.mobileid.go.kr:18888 # SP Server Address # 사용자(Client)에서 접근할 수 있는 검증자(Service Provider)의 IP Address : SP 서버 주소 app.sp-server=http://192.168.xxx.xxx:8080/egovframework-all-in-one ################################################################################# # SP & Wallet ################################################################################# # Wallet file path : 생성한 신분증 월렛 파일 경로 app.keymanager-path=/eGovFrameDev-4.1.0-64bit/workspace/egovframework-all-in-one-AllNew/src/main/resources/egovframework/mip/****.wallet # Wallet password : 생성 시 설정했던 신분증 월렛 패스워드 app.keymanager-password=**** # ECC key id : 생성 시 설정했던 sp key app.sp-key-id=****.sp # RSA key id : 생성 시 설정했던 rsa key app.sp-rsa-key-id=****.sp.rsa # SP blockchain account (SP 서비스 신청 승인 시 발급) : 모바일 운전면허증에서 발급 app.sp-account=****.sp # SP DID file path : 생성한 DID Document 파일 경로 app.sp-did-path=/eGovFrameDev-4.1.0-64bit/workspace/egovframework-all-in-one-AllNew/src/main/resources/egovframework/mip/****.did ==== 연계 구성 ==== - 모바일 신분증 개발지원센터에서 안내하는 연계 서비스 이용 절차에 따라 공문 접수 및 승인 후 DID 및 Wallet 파일을 생성하여 표준프레임워크 예제에 추가해 서비스 예제를 구성한다. - 표준프레임워크 공통컴포넌트에서 제공하는 모바일 운전면허증 연계 서비스 예제는 QR-MPM - direct mode 방식으로 연동 프로세스는 연계 순서도를 통해 확인할 수 있다. {{:egovframework:com:v4.1:sec:rnc:mip-flowchart.png|}} ===== 관련 기능 ===== ==== QR 코드 생성 ==== === 비즈니스 규칙 === SP 서버 정보와 트랜잭션 정보 등이 포함되어 있는 QR 코드를 요청하여 생성한다. === 관련코드 === /** * QR-MPM 시작 * * @MethodName : start * @param t510 QR-MPM 정보 * @return QR-MPM 정보 + Base64로 인코딩된 M200 메시지 * @throws SpException */ @Override public T510VO start(T510VO t510) throws SpException { LOGGER.debug("t510 : {}", ConfigBean.gson.toJson(t510)); String mode = t510.getMode(); String svcCode = t510.getSvcCode(); String branchName = t510.getBranchName(); String deviceId = t510.getDeviceId(); if (ObjectUtils.isEmpty(mode)) throw new SpException(MipErrorEnum.SP_MISSING_MANDATORY_ITEM, null, "t510.mode"); if (ObjectUtils.isEmpty(svcCode)) throw new SpException(MipErrorEnum.SP_MISSING_MANDATORY_ITEM, null, "t510.svcCode"); if (ObjectUtils.isEmpty(branchName)) throw new SpException(MipErrorEnum.SP_MISSING_MANDATORY_ITEM, null, "t510.branchName"); if (ObjectUtils.isEmpty(deviceId)) throw new SpException(MipErrorEnum.SP_MISSING_MANDATORY_ITEM, null, "t510.deviceId"); TrxInfoVO trxInfo = new TrxInfoVO(); trxInfo.setMode(mode); trxInfo.setSvcCode(svcCode); trxInfo.setBranchName(branchName); trxInfo.setDeviceId(deviceId); M200VO m200 = null; if (ModeEnum.DIRECT.getVal().equals(mode)) { m200 = this.directStart(trxInfo); } else { throw new SpException(MipErrorEnum.UNKNOWN_ERROR, null, "unsupported mode"); } String m200Str = ConfigBean.gson.toJson(m200); LOGGER.debug("m200Str : {}", m200Str); String m200Base64 = Base64Util.encode(m200Str); t510.setM200Base64(m200Base64); return t510; } /** * QR-MPM 시작(Direct 모드) * * @MethodName : directStart * @param trxInfo * @return * @throws SpException */ private M200VO directStart(TrxInfoVO trxInfo) throws SpException { String spServer = configBean.getSpServer(); String trxcode = Generator.genTrxcode(); String mode = trxInfo.getMode(); if (trxcode == null) { throw new SpException(MipErrorEnum.UNKNOWN_ERROR, null, "거래코드 생성 실패"); } trxInfo.setTrxcode(trxcode); trxInfoService.registTrxInfo(trxInfo); M200VO m200 = new M200VO(); m200.setType(ConfigBean.TYPE); m200.setVersion(ConfigBean.VERSION); m200.setCmd(ConfigBean.M200); m200.setTrxcode(trxcode); m200.setMode(mode); m200.setHost(spServer); return m200; } * 모바일 운전면허증 QR 정보 요청 화면 예 {{:egovframework:com:v4.1:sec:rnc:mip-qr.png|}} ==== 사용자 검증 ==== === 비즈니스 규칙 === 모바일 신분증 어플리케이션을 통한 QR 촬영으로 모바일 신분증 내 VP를 검증자에게 직접 전달하여 사용자 검증을 진행한다. === 관련코드 === /** * VP 검증 * * @MethodName : verifyVP * @param trxcode 거래코드 * @param vp VP 정보 * @return 검증 결과 * @throws SpException */ @Override public Boolean verifyVP(String trxcode, VP vp) throws SpException { LOGGER.debug("trxcode : {}, vp : {}", trxcode, ConfigBean.gson.toJson(vp)); Boolean result = false; TrxInfoVO trxInfo = new TrxInfoVO(); trxInfo.setTrxcode(trxcode); trxInfo.setTrxStsCode(TrxStsCodeEnum.VERIFY_REQ.getVal()); trxInfoService.modifyTrxInfo(trxInfo); Integer encryptType = vp.getEncryptType(); Integer keyType = vp.getKeyType(); String type = vp.getType(); String data = vp.getData(); List authType = vp.getAuthType(); String did = vp.getDid(); String nonce = vp.getNonce(); // VP 검증 Start VCVerifyProfileResult vCVerifyProfileResult = new VCVerifyProfileResult(); vCVerifyProfileResult.setEncryptType(encryptType); vCVerifyProfileResult.setKeyType(keyType); vCVerifyProfileResult.setType(type); vCVerifyProfileResult.setData(data); vCVerifyProfileResult.setAuthType(authType); vCVerifyProfileResult.setDid(did); vCVerifyProfileResult.setNonce(nonce); ResultJson resultJson = this.verify(vCVerifyProfileResult, trxcode); if (resultJson == null || !resultJson.isResult()) { return result; } // VP 검증 End // VP 상태 확인 Start Map vpDataMap = null; EncryptKeyTypeEnum keyTypeEnum = EncryptKeyTypeEnum.getEnum(vCVerifyProfileResult.getKeyType()); if (keyTypeEnum == EncryptKeyTypeEnum.ALGORITHM_RSA) { try { AESType aESType = vCVerifyProfileResult.getEncryptType() == 1 ? AESType.AES128 : AESType.AES256; byte[] vpDataByte = keyManager.rsaDecrypt(configBean.getSpRsaKeyId(), HexUtils.toBytes(vCVerifyProfileResult.getData()), aESType); data = new String(vpDataByte, StandardCharsets.UTF_8); LOGGER.debug("data : {}", data); } catch (IWException e) { throw new SpException(MipErrorEnum.UNKNOWN_ERROR, trxcode, e.getErrorMsg()); } } try { vpDataMap = ConfigBean.gson.fromJson(data, HashMap.class); } catch (JsonSyntaxException e) { throw new SpException(MipErrorEnum.SP_UNEXPECTED_MSG_FORMAT, trxcode, "data"); } List> verifiableCredentialList = (List>) vpDataMap.get("verifiableCredential"); if (ObjectUtils.isEmpty(verifiableCredentialList)) { throw new SpException(MipErrorEnum.SP_UNEXPECTED_MSG_FORMAT, trxcode, "vp"); } Map verifiableCredential = verifiableCredentialList.get(0); String vcId = (String) verifiableCredential.get("id"); ResultVcStatus resultVcStatus = null; try { resultVcStatus = this.getVCStatus(vcId); } catch (BlockChainException e) { throw new SpException(MipErrorEnum.UNKNOWN_ERROR, trxcode, e.getErrorMsg()); } String vcStatus = resultVcStatus.getVcStatus(); if (vcStatus.equalsIgnoreCase(VcStatusEnum.ACTIVE.getVal())) { // 활성화 상태 result = true; } else if (vcStatus.equalsIgnoreCase(VcStatusEnum.NEED_RENEW.getVal())) { // 갱신필요 상태 String memo = resultVcStatus.getMemo(); if (memo.equals("주소변경")) { result = true; } else { throw new SpException(MipErrorEnum.UNKNOWN_ERROR, trxcode, "제출불가 상태 : " + vcStatus + "(" + memo + ")"); } } else { throw new SpException(MipErrorEnum.UNKNOWN_ERROR, trxcode, "제출불가 상태 : " + vcStatus); } // VP 상태 확인 End // Nonce 위변조 확인 Start TrxInfoVO curTrxInfo = trxInfoService.getTrxInfo(trxcode); if (curTrxInfo == null) { throw new SpException(MipErrorEnum.SP_TRXCODE_NOT_FOUND, trxcode); } String curVpVerifyResult = curTrxInfo.getVpVerifyResult(); // 이미 verify 된 trx if ("Y".equals(curVpVerifyResult)) { throw new SpException(MipErrorEnum.SP_MSG_SEQ_ERROR, trxcode, "verifyResult == Y"); } String profileNonce = curTrxInfo.getNonce(); // 일반인증시 proof를 사용하고 안심인증시 proofs를 사용 Map proof = (Map) vpDataMap.get("proof"); List> proofs = (List>) vpDataMap.get("proofs"); if (ObjectUtils.isEmpty(proof) && ObjectUtils.isEmpty(proofs)) { throw new SpException(MipErrorEnum.SP_UNEXPECTED_MSG_FORMAT, trxcode, "proof"); } if (!ObjectUtils.isEmpty(proof)) { String vpNonce = (String) proof.get("nonce"); LOGGER.debug("profileNonce : {}, vpNonce : {}", profileNonce, vpNonce); if (!profileNonce.equals(vpNonce)) { throw new SpException(MipErrorEnum.SP_MISMATCHING_NONCE, trxcode); } } if (!ObjectUtils.isEmpty(proofs)) { for (Map obj : proofs) { String vpNonce = (String) obj.get("nonce"); LOGGER.debug("profileNonce : {}, vpNonce : {}", profileNonce, vpNonce); if (!profileNonce.equals(vpNonce)) { throw new SpException(MipErrorEnum.SP_MISMATCHING_NONCE, trxcode); } } } // Nonce 위변조 확인 End String vpVerifyResult = result ? "Y" : "N"; trxInfo.setTrxcode(trxcode); trxInfo.setTrxStsCode(TrxStsCodeEnum.VERIFY_COM.getVal()); trxInfo.setVpVerifyResult(vpVerifyResult); // VP 정보 추출 및 저장 if(result) { Map credentialSubject = (Map) verifiableCredentialList.get(8).get("credentialSubject"); List> privacy = (List>) credentialSubject.get("privacy"); trxInfo.setVpName((String) privacy.get(0).get("value")); } // VP 정보 추출 및 저장 End trxInfoService.modifyTrxInfo(trxInfo); return result; } ==== 검증 결과 조회 ==== === 비즈니스 규칙 === 트랜잭션 처리 정보를 조회한다. === 관련코드 === /** * 거래상태 조회 * * @param mipApiData {"data":"Base64로 인코딩된 TrxInfoVO"} * @return {"result":true, "data":"Base64로 인코딩된 TrxInfoVO"} * @throws SpException */ @RequestMapping(value = "/trxsts") public MipApiDataVO getTrxsts(@RequestBody MipApiDataVO mipApiData) throws SpException { LOGGER.debug("거래상태 조회!"); String data = Base64Util.decode(mipApiData.getData()); TrxInfoVO trxInfo = null; try { trxInfo = ConfigBean.gson.fromJson(data, TrxInfoVO.class); } catch (JsonSyntaxException e) { throw new SpException(MipErrorEnum.SP_UNEXPECTED_MSG_FORMAT, null, "trxInfo"); } trxInfo = trxInfoService.getTrxInfo(trxInfo.getTrxcode()); mipApiData.setResult(true); mipApiData.setData(Base64Util.encode(ConfigBean.gson.toJson(trxInfo))); return mipApiData; } * 모바일 운전면허증 트랜잭션 정보 조회 예 {{:egovframework:com:v4.1:sec:rnc:mip-tx.png|}}