diff --git a/web3-credential-server/build/resources/main/data.sql b/web3-credential-server/build/resources/main/data.sql index 3147753..c0bfdf0 100644 --- a/web3-credential-server/build/resources/main/data.sql +++ b/web3-credential-server/build/resources/main/data.sql @@ -4,6 +4,7 @@ VALUES ('exampleuser@example.com', '$2a$10$EXAMPLEHASHFORUSERPASSWORD'), ('3751271433', '$2a$10$skVt4kLn.95UGnrasmxQku5AGhhg6fESNtg/Ndw3iBQin.SqHrIdK'); + INSERT INTO wallets (user_id, pdfUrl,privateKey, publicKey) VALUES (1,'https://basilium-product-bucket.s3.ap-northeast-2.amazonaws.com/1_certifications.pdf','privateKeyForUser1', 'publicKeyForUser1'), @@ -11,4 +12,3 @@ VALUES (3,null,'privateKeyForUser2', 'publicKeyForUser2'); - diff --git a/web3-credential-server/build/tmp/compileJava/previous-compilation-data.bin b/web3-credential-server/build/tmp/compileJava/previous-compilation-data.bin index 889e4c3..ea5dd42 100644 Binary files a/web3-credential-server/build/tmp/compileJava/previous-compilation-data.bin and b/web3-credential-server/build/tmp/compileJava/previous-compilation-data.bin differ diff --git a/web3-credential-server/src/main/java/web3/controller/Identity/IdentityController.java b/web3-credential-server/src/main/java/web3/controller/Identity/IdentityController.java index 714034d..a80f478 100644 --- a/web3-credential-server/src/main/java/web3/controller/Identity/IdentityController.java +++ b/web3-credential-server/src/main/java/web3/controller/Identity/IdentityController.java @@ -18,6 +18,7 @@ import web3.service.wallet.WalletService; import java.io.IOException; +import java.time.LocalDateTime; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -45,8 +46,8 @@ public ResponseEntity registerCertification( @RequestParam("univName") String univName, @RequestParam("univCheck") Boolean univCheck) { - StudentCertificationDto certificationDto = new StudentCertificationDto(email, univName, univCheck); - + LocalDateTime certifiedDate = LocalDateTime.now(); // 현재 시간 + StudentCertificationDto certificationDto = new StudentCertificationDto(email, univName, univCheck, certifiedDate); identityService.registerStudentCertification(walletId, certificationDto, file); return ResponseEntity.ok("재학증이 성공적으로 등록되었습니다."); diff --git a/web3-credential-server/src/main/java/web3/controller/cert/PassportController.java b/web3-credential-server/src/main/java/web3/controller/cert/PassportController.java new file mode 100644 index 0000000..3395287 --- /dev/null +++ b/web3-credential-server/src/main/java/web3/controller/cert/PassportController.java @@ -0,0 +1,58 @@ +package web3.controller.cert; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import reactor.core.publisher.Mono; +import web3.service.cert.PassportService; +import web3.service.dto.cert.PassportRequestDto; + +import java.io.IOException; +import java.util.Base64; + +@RestController +@RequestMapping("/api/passport") +public class PassportController { + + private final PassportService passportService; + + public PassportController(PassportService passportService) { + this.passportService = passportService; + } + + @Operation(summary = "여권 유효성 검사", description = "여권의 유효성을 검사합니다.") + @PostMapping("/check-validity") + public Mono> checkPassportValidity( + @Parameter(description = "여권 요청 정보", required = true) + @RequestParam("certFile") MultipartFile certFile, + @RequestParam("keyFile") MultipartFile keyFile, + @RequestParam("certPassword") String certPassword, + @RequestParam("userName") String userName, + @RequestParam("identity") String identity, + @RequestParam("passportNo") String passportNo, + @RequestParam("issueDate") String issueDate, + @RequestParam("expirationDate") String expirationDate, + @RequestParam("birthDate") String birthDate) { + + String certFileEncoded = encodeFileToBase64(certFile); + String keyFileEncoded = encodeFileToBase64(keyFile); + + PassportRequestDto passportRequestDto = new PassportRequestDto(certFileEncoded, keyFileEncoded, certPassword, userName, identity, passportNo, issueDate, expirationDate, birthDate); + + return passportService.checkPassportValidity(passportRequestDto) + .map(response -> ResponseEntity.ok("여권 유효성 검사 성공: " + response)) + .onErrorReturn(ResponseEntity.badRequest().body("여권 유효성 검사에 실패했습니다.")); + } + + private String encodeFileToBase64(MultipartFile file) { + try { + byte[] fileContent = file.getBytes(); + return Base64.getEncoder().encodeToString(fileContent); + } catch (IOException e) { + throw new RuntimeException("파일 인코딩 실패", e); + } + } + +} diff --git a/web3-credential-server/src/main/java/web3/service/Identity/IdentityService.java b/web3-credential-server/src/main/java/web3/service/Identity/IdentityService.java index 2f41e51..a9a7510 100644 --- a/web3-credential-server/src/main/java/web3/service/Identity/IdentityService.java +++ b/web3-credential-server/src/main/java/web3/service/Identity/IdentityService.java @@ -53,10 +53,11 @@ public void registerStudentCertification(Long walletId, StudentCertificationDto // 메타데이터 키 및 문자열 생성 // 등록 및 인증시간 포함하기 String metadataKey = "재학증_" + walletId; - String metadataString = String.format("{\"email\":\"%s\",\"univName\":\"%s\",\"univ_check\":%b}", + String metadataString = String.format("{\"email\":\"%s\",\"univName\":\"%s\",\"univ_check\":%b,\"certified_date\":\"%s\"}", certificationDto.getEmail(), certificationDto.getUnivName(), - certificationDto.isUnivCheck()); + certificationDto.isUnivCheck(), + certificationDto.getCertifiedDate()); String fileName = generatePdfFileName(walletId); byte[] result; diff --git a/web3-credential-server/src/main/java/web3/service/cert/PassportService.java b/web3-credential-server/src/main/java/web3/service/cert/PassportService.java new file mode 100644 index 0000000..86b0b98 --- /dev/null +++ b/web3-credential-server/src/main/java/web3/service/cert/PassportService.java @@ -0,0 +1,116 @@ +package web3.service.cert; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; +import web3.service.dto.cert.PassportRequestDto; + +import javax.crypto.Cipher; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +@Service +@Slf4j +public class PassportService { + + private final WebClient webClient; + private final WebClient webClientToken; // 액세스 토큰 요청을 위한 WebClient + private static final String BASE_URL = "https://development.codef.io"; + private static final String API_URL = "/v1/kr/public/mw/passport-data/status"; + private static final String BASE_TOKEN_URL = "https://oauth.codef.io"; + private static final String ACCESS_TOKEN_URL = "/oauth/token"; + private static final String CLIENT_ID = "86640213-3b83-461a-97ab-2491d68a2052"; + + public PassportService(WebClient.Builder webClientBuilder) { + this.webClient = webClientBuilder.baseUrl(BASE_URL).build(); + this.webClientToken = webClientBuilder.baseUrl(BASE_TOKEN_URL).build(); // 수정된 부분 + } + + // 액세스 토큰을 가져오는 메서드 + private Mono fetchAccessToken() { + return webClientToken.post() + .uri(ACCESS_TOKEN_URL) // 추가된 경로 + .header("Authorization", "Basic " + Base64.getEncoder().encodeToString((CLIENT_ID + ":" + CLIENT_SECRET).getBytes())) + .header("Content-Type", "application/x-www-form-urlencoded") + .bodyValue("grant_type=client_credentials&scope=read") + .retrieve() + .bodyToMono(Map.class) + .map(response -> (String) response.get("access_token")) + .doOnError(e -> log.error("Error fetching access token: {}", e.getMessage())); + } + + // RSA 암호화 메서드 + private String encryptRSAPassword(String password) throws Exception { + byte[] keyBytes = Base64.getDecoder().decode(PUBLIC_KEY_STR); + PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(keyBytes)); + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + return Base64.getEncoder().encodeToString(cipher.doFinal(password.getBytes(StandardCharsets.UTF_8))); + } + + // 패스포트 유효성 검사 메서드 + public Mono> checkPassportValidity(PassportRequestDto passportRequestDto) { + return fetchAccessToken() + .flatMap(accessToken -> { + try { + Map requestBody = createRequestBody(passportRequestDto); + log.info("requestBody: {}", requestBody); + return webClient.post() + .uri(API_URL) + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .bodyValue(requestBody) + .retrieve() + .bodyToMono(String.class) + .flatMap(responseBody -> { + log.info("Response: {}", responseBody); + ObjectMapper objectMapper = new ObjectMapper(); + try { + String decodedResponseBody = URLDecoder.decode(responseBody, StandardCharsets.UTF_8.name()); + Map jsonResponse = objectMapper.readValue(decodedResponseBody, new TypeReference>() {}); + return Mono.just(jsonResponse); + } catch (JsonProcessingException e) { + log.error("Error processing JSON: {}", e.getMessage()); + return Mono.error(e); // 예외를 반환 + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + }) + .doOnError(e -> log.error("Error checking passport validity: {}", e.getMessage())); + } catch (Exception e) { + return Mono.error(e); + } + }); + } + + private Map createRequestBody(PassportRequestDto passportRequestDto) throws Exception { + Map requestBody = new HashMap<>(); + requestBody.put("organization", "0002"); + requestBody.put("loginType", "2"); + requestBody.put("certType", "1"); + requestBody.put("certFile", passportRequestDto.getCertFileEncoded()); + requestBody.put("keyFile", passportRequestDto.getKeyFileEncoded()); + requestBody.put("certPassword", encryptRSAPassword(passportRequestDto.getCertPassword())); + requestBody.put("userName", passportRequestDto.getUserName()); + requestBody.put("userName1", passportRequestDto.getUserName()); + requestBody.put("identity", passportRequestDto.getIdentity()); + requestBody.put("passportNo", passportRequestDto.getPassportNo()); + requestBody.put("issueDate", passportRequestDto.getIssueDate()); + requestBody.put("expirationDate", passportRequestDto.getExpirationDate()); + requestBody.put("birthDate", passportRequestDto.getBirthDate()); + return requestBody; + } +} diff --git a/web3-credential-server/src/main/java/web3/service/dto/Identity/StudentCertificationDto.java b/web3-credential-server/src/main/java/web3/service/dto/Identity/StudentCertificationDto.java index ee7f4a1..f693cfa 100644 --- a/web3-credential-server/src/main/java/web3/service/dto/Identity/StudentCertificationDto.java +++ b/web3-credential-server/src/main/java/web3/service/dto/Identity/StudentCertificationDto.java @@ -1,15 +1,22 @@ package web3.service.dto.Identity; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + public class StudentCertificationDto { private String email; private String univName; private boolean univCheck; + private LocalDateTime certifiedDate; // 새로운 필드 추가 - public StudentCertificationDto(String email, String univName, boolean univCheck) { + public StudentCertificationDto(String email, String univName, boolean univCheck, LocalDateTime certifiedDate) { this.email = email; this.univName = univName; this.univCheck = univCheck; + this.certifiedDate = certifiedDate; // 새로운 필드 초기화 } public String getEmail() { @@ -24,4 +31,8 @@ public boolean isUnivCheck() { return univCheck; } + public String getCertifiedDate() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm"); + return certifiedDate.format(formatter); + } } diff --git a/web3-credential-server/src/main/java/web3/service/dto/cert/PassportRequestDto.java b/web3-credential-server/src/main/java/web3/service/dto/cert/PassportRequestDto.java new file mode 100644 index 0000000..25e4b8e --- /dev/null +++ b/web3-credential-server/src/main/java/web3/service/dto/cert/PassportRequestDto.java @@ -0,0 +1,64 @@ +package web3.service.dto.cert; + +public class PassportRequestDto { + private String certFileEncoded; // 인증서 파일 Base64 인코딩 + private String keyFileEncoded; // 키 파일 Base64 인코딩 + private String certPassword; // 인증서 비밀번호 + private String userName; // 사용자 이름 + private String identity; // 주민등록번호 + private String passportNo; // 여권 번호 + private String issueDate; // 발급일 + private String expirationDate; // 만료일 + private String birthDate; // 생년월일 + + public PassportRequestDto(String certFileEncoded, String keyFileEncoded, String certPassword, + String userName, String identity, String passportNo, + String issueDate, String expirationDate, String birthDate) { + this.certFileEncoded = certFileEncoded; + this.keyFileEncoded = keyFileEncoded; + this.certPassword = certPassword; + this.userName = userName; + this.identity = identity; + this.passportNo = passportNo; + this.issueDate = issueDate; + this.expirationDate = expirationDate; + this.birthDate = birthDate; + } + + // Getters + public String getCertFileEncoded() { + return certFileEncoded; + } + + public String getKeyFileEncoded() { + return keyFileEncoded; + } + + public String getCertPassword() { + return certPassword; + } + + public String getUserName() { + return userName; + } + + public String getIdentity() { + return identity; + } + + public String getPassportNo() { + return passportNo; + } + + public String getIssueDate() { + return issueDate; + } + + public String getExpirationDate() { + return expirationDate; + } + + public String getBirthDate() { + return birthDate; + } +} diff --git a/web3-credential-server/src/main/resources/data.sql b/web3-credential-server/src/main/resources/data.sql index 3147753..f55d955 100644 --- a/web3-credential-server/src/main/resources/data.sql +++ b/web3-credential-server/src/main/resources/data.sql @@ -4,11 +4,9 @@ VALUES ('exampleuser@example.com', '$2a$10$EXAMPLEHASHFORUSERPASSWORD'), ('3751271433', '$2a$10$skVt4kLn.95UGnrasmxQku5AGhhg6fESNtg/Ndw3iBQin.SqHrIdK'); + INSERT INTO wallets (user_id, pdfUrl,privateKey, publicKey) VALUES (1,'https://basilium-product-bucket.s3.ap-northeast-2.amazonaws.com/1_certifications.pdf','privateKeyForUser1', 'publicKeyForUser1'), (2,null,'privateKeyForUser2', 'publicKeyForUser2'), - (3,null,'privateKeyForUser2', 'publicKeyForUser2'); - - - + (3,null,'privateKeyForUser2', 'publicKeyForUser2'); \ No newline at end of file