본문 바로가기
프로젝트/장애인 PT 플랫폼, PTFD

PortOne을 활용한 간단 결제단 구축

by 임지혁코딩 2024. 2. 11.

 

 

결제 정보가 요청된다. 

test channel이기 때문에, 금액 상관 없이 결제가 가능하다. 

 

이와 같이, 결제가 생성된다. 

 

<실 연동을 위해선 , 사업자 등록증이 필요하다. >

 

고려할점 - 

현재 매우매우 간단하게 제공된 툴로 JS단에서 결제를 구성했다.

이런 간단한 수준만의 결제는 결과 적으론 의미가 있을 수 있어도, 프로젝트 측면에선 의미가 약하다고 판단.

 

빌링키 조회 API를 활용하여 REST API로 백에게 전 권한을 위임하여 통신하는 방식으로 변경해야겠다고 생각했다. 

 

 

<결제 확인단 형태만 구축>

 

@RestController
@Slf4j
public class PaymentController {

    private final WebClient webClient;

    public PaymentController(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder.baseUrl("https://api.portone.io").build();
    }

    @PostMapping("/payments/complete")
    public Mono<ResponseEntity<?>> completePayment(@RequestBody ValidationRequest validation) {
        log.info("CALL OK");

        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("apiSecret", "실제발급받은secret");

        return webClient.post()
                .uri("/login/api-secret")
                .bodyValue(requestBody)
                .retrieve()
                .bodyToMono(PortoneResponse.class)
                .flatMap(portoneresponse -> {
                    String mytoken = portoneresponse.getAccessToken();
                    // 토큰 획득
                    log.info("mytoken", mytoken);

                    return webClient.get()
                            .uri("/payments/{paymentId}", validation.getPaymentId())
                            .header("Authorization", "Bearer " + mytoken)
                            .retrieve()
                            .bodyToMono(PurChaseCheck.class)
                            .map(purchaseCheck -> {
                                // 결제 금액 가져오기
                                if (purchaseCheck.getAmount().equals(300)) {
                                    return ResponseEntity.ok(purchaseCheck);
                                    //원래는 이부분에서 엄청 많아야됨
                                    //db랑 검사, 결제금ㅇ낵이랑 요청금액 검사, 등등
                                    //그리고 이상하면, 여기서 취소 요청을 다시보내야함 !
                                    //이게 spring이랑 분할했을때 좀 번거로움
                                    // 근데 정책문제로 spring만으로 결제가 안될수도있음 .. 생가기필요
                                } else {
                                    return ResponseEntity.badRequest().build();
                                }
                            });
                });
    }

 

 

정말 간단하게, 검증하는 형태만 구현하고 상세 로직은 구현하지 않았다.

 

실제 부분은 

1. 결제 금액에 대한 확인

2. 결제 금액과 db에 저장된 상품의 금액 확인

3. 문제 발생시 주문 취소 요청 재 호출이 필요하다. 

 

*현재 V2로 버전이 업그레이드 되며 API SECRET을 별도로 발급받아야 하여, 401 NO AUTORICATION이 발생했다.

 

js에서 비동기적 형태의 전송을 진행하기 때문에, 쓰레드가 자동으로 java의 webclient를 비동기로 인식한다. 

그러므로 동기적인 . block()을 사용했을때 오류가 발생했다. 

그러므로 purchase Check를 활용하여, 비동기적 전송으로 변경하게 되었다. 

 

<고민해야 할 점> 

 

1. '정책'의 문제로, 사용자의 카드 정보를 가맹점에서 저장하는 것이 불가능 한 것으로 알려져 있다.

그렇다면, js를 활용하지 않고 spring 상으로 카드 정보를 받아 RESTAPI를 전송하는 형태는 불가능 한 것일까? 

 

빌링키를 받아 , SRPING을 활용한 백엔드 단에서 결제가 가능하다. 

이를 활용하는 방안으로 최종 결제 과정을 변경하는 것이 유리해 보인다. 

 

고객사가 고객의 카드정보를 저장할 수 없기 때문에, 해당 카드에 대응하는 빌링키를 발급 받아 저장하고, 결제 시점에는 결제 정보 대신 빌링키를 이용하여 요청하는 방식을 사용할 수 있다.

 

#다만.. 해당 내역이 test channel에도 가능한지 등의 요소는 검증이 필요하다. 

 

사용자 인증을 내 서버에서 담당해야 하기 떄문에, SPRING SECURITY를 활용하면 좋을 것 같다는 조언을 받기도 하였다. 

 

<다음 목표>

 

 

이와 같이, 인증에 mytoken을 header로 추가해서 js를 활용한 결제 구조를 일단락 지었다 .

 

즉 현재 구현한 형태는

 

결제(js를 활용한 front) -> portone에서 결제 id를 받아온다

결제(js를 활용한 front) - > 받아온 결제 id + 요청으로 받은 인증 token 을 통하여 backend에 다시 전달

backend -> 결제 id + token으로 결제 정보를 실제 db의 금액등 과 확인

문제가 없을시 취소하지 않고 진행한다. 

 

세부 검증 과정은, 모든걸 backend로 이임한 이후에 진행하도록 하겠다. 

 

--에러 -- 

  1. {message: 'Request failed with status code 400', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}

이와 같은 에러가 현재 발생하고 있다. 이를 수정할 방법을 고민해 봐야겠다. 

 

<수정 완료> 

현재 받아왔던 형태 그대로 받아서 사용했었는데, 이를 인지하지 못하고 amount만을 값으로 제출하려 하였다. 

수정 완료!