티스토리 뷰

Web

포트원 웹훅 결제 검증

tose33 2024. 2. 27. 21:48

https://developers.portone.io/docs/ko/readme/get-started?v=v1

 

GET STARTED

 

developers.portone.io

 

 

프로젝트에 포트원 결제 시스템을 구현해 놓았었다.

아래 포트원의 공식 레퍼런스에 결제정보 사후 검증하기 항목이 있다.

 

https://developers.portone.io/docs/ko/auth/guide/5/post?v=v1

 

결제정보 사후 검증하기

결제정보 사후 검증하기 결제 정보를 사후 검증하는 과정은 크게 세 단계로 이루어집니다. 응답받은 내용을 바탕으로 실 결제 금액과 결제요청금액(가맹점 자체 데이터베이스)을 비교 결제 상

developers.portone.io

 

클라이언트는 얼마든지 위변조가 가능하기 때문에 실제로 클라이언트에서 결제한 값과, 내 서버의 db의 상품의 실제 값을 비교해서 같은 값인지 아닌지 검증하는 것이다.

 

이런 과정이 없다면 예를들어 실제 상품의 가격은 10000원인데 클라이언트에서 100원으로 바꿔서 결제를 해도 서버는 그냥 결제성공이라고만 전달 받고 성공 처리할것이다.

 

사후검증도 기존에 구현은 해놨었다.

기존의 방식은 아래와 같았다

  • 클라이언트에서 포트원 서버에 결제 요청을 한다
  • 결제 성공했다면 내 서버에 결제 성공했다고 알린다
  • 내 서버에서 포트원 서버에 결제내역을 조회해서 내 DB에 저장된 실제 상품의 가격과 대조해본다

 

그런데 레퍼런스를 보면 웹훅을 사용해야 한다고 한다.

그래서 이번에 로직을 웹훅을 사용하도록 바꿔봤다.

 

웹훅이란?

우선 웹훅이 뭔지 간단하게 기록해보면 폴링(Polling)의 반대이다.

일반적인 서버-클라이언트는 클라이언트가 서버를 호출하는 형태이다.

웹훅은 그 반대로 서버에서 클라이언트로 신호를 보내는 방식이다.

그리고 서버측에서 클라이언트의 어떤 url 로 신호를 보낼지 정해놓은 주소를 callback url 이라고 한다.

 

웹훅이 왜 필요한지는 이번에 구현하는 포트원 웹훅을 보면 명확하다.

 

 

왜 웹훅으로 결제 검증 하는가

기존에 구현한 결제 사후 검증 로직은 허점이 있다.

클라이언트에서 포트원 서버에 결제 요청을 하고 결제가 성공했다면 신호를 클라이언트에서 받는다.

그 후 클라이언트에서 내 서버로 결제검증을 위한 요청을 할텐데, 이때 클라이언트와의 연결이 끊어질수가 있다.

와이파이 상태, 브라우저 자동 리로드등 클라이언트의 상태는 내가 컨트롤할수가 없다. 

 

포트원에서 웹훅을 제공하는 이유는 이런 상황 때문이다.

내 서버로 결제 검증을 위한 요청을 포트원 서버에서 내 서버로 웹훅을 보내주면, 유저 클라이언트의 상태가 어떻든 무조건 결제 검증을 수행할수 있다.

 

 

구현

 

https://developers.portone.io/docs/ko/result/webhook?v=v1

 

웹훅(Webhook) 연동하기

웹훅(Webhook) 연동하기 웹훅 연동을 통해 결제 결과를 안전하게 처리하실 수 있습니다. 포트원 웹훅(webhook)을 사용하여 포트원 서버에 저장된 결제 정보를 가맹점 서버에 동기화하고 네트워크 불

developers.portone.io

 

 

포트원 웹훅(webhook)은 다음과 같은 경우에 호출됩니다.

  • 결제가 승인되었을 때(모든 결제 수단) - (status : paid)
  • 가상계좌가 발급되었을 때 - (status : ready)
  • 가상계좌에 결제 금액이 입금되었을 때 - (status : paid)
  • 예약결제가 시도되었을 때 - (status : paid or failed)
  • 관리자 콘솔에서 결제 취소되었을 때 - (status : cancelled)

 

 

Webhook POST 요청의 본문은 다음의 정보를 포함합니다. 가맹점 서버는 해당 정보를 수신하고 포트원 서버에서 결제 정보를 조회하여 검증 및 저장할 수 있습니다.

  • imp_uid : 결제번호
  • merchant_uid : 주문번호
  • status : 결제 결과
  • cancellation_id : 취소내역 아이디

 

레퍼런스에 내용에 따라 서버에서는 아래와 비슷하게 웹훅의 엔드포인트를 만들면 된다.

// 포트원 웹훅 엔드포인트
    @PostMapping("/portone-webhook")
    public ResponseEntity<String> portOneWebhook(@RequestParam String status, @RequestParam String imp_uid, @RequestParam String merchant_uid,
                                                  HttpSession session, Principal principal){

    }

 

위와 같이 엔드포인트에서 받아서 status 의 내용에 따라 분기해주면 된다.

  • 클라이언트에서 포트원 서버에 결제 요청을 한다
  • 결제 성공했다면 포트원 서버에서 웹훅으로 내 서버의 엔드포인트로 신호를 보낸다
  • 내 서버 엔드포인트에서 받고 결제 검증한다 


문제점

사실 웹훅을 엔드포인트에서 받고 처리하는것 자체는 어려울게 없었다.

내가 기록하기로 한 이유는 구현중 골치아픈 문제가 있어서였다.

 

웹훅 도입전, 나는 결제폼에서 사용자에게 배송정보(주소), 이메일등을 입력받고 클라이언트에서 포트원에 결제 요청을 한 후에 성공하면 포트원에서 클라이언트에 보내준 결제정보와 사용자가 입력한 정보들을 한번에 내 서버로 전송해서 처리했다.

 

웹훅으로 결제 사후 검증을 하기로 했을때 문제가 있었다.

웹훅이 없었을때는 그냥 포트원의 결제정보와 사용자가 클라이언트에서 입력한 정보를 한번에 서버에서 보내서 문제가 없었다.

 

그런데 웹훅으로 결제 검증을 하려면, 사용자가 입력한 정보를 내 서버로 보내는 요청과, 웹훅의 결제 검증 로직을 분리해야 했다.

 

처음에는 우선 사용자가 입력한 정보를 내 서버로 보낸후에 세션에 저장하고,

웹훅으로 요청이 오면 세션에서 꺼내서 검증후 DB 저장처리 하려고 했다.

 

그런데 생각해보면 너무 당연하게도 사용자가 입력한 정보는 사용자의 클라이언트에서 온 요청이고, 

웹훅은 포트원 서버에서 온 요청이기 때문에 세션이 서로 다르다.

 

이 부분에서 고민을 했다.

 

해결

웹훅이란것 자체를 처음 접해봐서 좀 당황했지만 해결하고 보니 방법은 간단했다.

 

포트원에서 보내는 웹훅에는 주문번호 merchant_uid 가 포함되어 있다.

이 merchant_uid 를 식별자로 하면 된다.

 

즉 사용자가 입력한 정보를 우선 DB에 저장한다. 

이때 merchant_uid 를 포함해 저장한다.

 

나중에 웹훅에서 요청이 오면 merchant_uid 로 DB에서 저장한 사용자 정보를 가져온다.

그 후 결제 검증을 마친후 결제 객체 (payment) 에 포트원 웹훅에 포함된 정보들을 저장하면 된다.

 

 

 

내가 고민했던 점은, 사용자 정보를 저장 요청과 포트원 웹훅 요청이 따로따로 서로 다른 클라이언트에서 오기 때문에 생긴 고민이었다.

웹훅을 사용하기 전 처럼 DB에 한번에 정보들을 저장하고 싶었는데 서로 다른 클라이언트에서 요청이 두번 오기 때문에 아무리 생각해도 그럴수는 없을것 같다.

 

사용자 정보를 먼저 DB에 저장해놓고,

포트원 웹훅 요청이 오면 결제 정보들을 다시 DB에 넣는다.

'Web' 카테고리의 다른 글

thymeleaf) 객체의 리스트 클라이언트에 전달하기  (0) 2024.02.08
InstawebV2 완료, 변경점  (0) 2023.12.28
Spring 순환 참조 해결  (0) 2023.12.19
OAuth2 로그인 시스템 구조 리팩토링  (0) 2023.12.06
Spring WebClient  (0) 2023.11.13
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함