배민페이처럼 결제정보를 서버에 등록하여 클라이언트가 편하게 결제를 할 수 있는 방식을 구현해보기로 함...!
인증결제 같은경우는 사용자가 구매를 할때마다, 직접 결제를 해야하기 때문에 불편함..
하지만 결제에 대한 결과를 PortOne 서버에 API 요청만 하면 알수 있어서 가장 안전하고 간단한 방법이다!
https://portone.gitbook.io/docs/auth/guide (포트원인증결제 Doc)
[포트원 비인증결제 공식 문서] https://portone.gitbook.io/docs/auth/guide-1
- 서비스 서버에 직접 사용자의 결제정보를 저장해놓는 것은 위험하고, 또 서버 단독으로 결제를 발생시킬 수 없다.
- 결제를 직접 승인해주는 제 3의 결제 제공사 PaymentGateway가 필요함
- 비인증 결제에는 두 가지 방식이 존재한다.
여기서 결제정보를 저장하는 빌링키 결제 방식을 택하기로 하였다!
https://developers.portone.io/docs/ko/auth/guide-1/bill/readme
빌링키 결제 구현에도 두가지 방법이 있다 {REST API 이용, PG결제창 이용}
포트원 REST API 를 이용하여 빌링키를 획득하여 결제를 요청할 수 있습니다. 고객 카드정보를 이용하여 빌링키 발급을 요청하면 포트원 서버가 PG사의 API를 호출하여 빌링키를 발급받습니다. 이 과정에서 카드정보는 기록되지 않습니다.이 방식은 다음과 같은 특징이 있습니다.
장점: 가맹점이 원하는 형태의 화면으로 카드정보 입력란을 커스터마이징할 수 있다.
단점: 개인정보 이용약관을 명시해야 하며 PG사 및 카드사 심사가 까다롭고 개인정보 유출에 유의해야 합니다.
PG사가 제공하는 일반 결제창에 고객이 카드정보를 입력하여 빌링키를 발급 받을수 있습니다.
장점: 카드정보가 서버 또는 포트원의 서버를 거치지 않고 직접 PG사로 전달되기 때문에 데이터 및 통신구간 암호화 등의 추가 보안 프로세스가 없다.
단점: PG사의 일반결제창을 통해 카드정보를 입력받기 때문에 웹브라우저를 통해서만 빌링키 발급이 이루어지며, 카드정보 입력란을 커스터마이징 할 수 없다.(가맹점 사이트 친화적인 UI/UX 구성불가)
카드 등록도 서비스단에서 구현을 하기로 결정해서 REST API를 통해서 카드정보 입력란 등을 직접 만들기로 하여 REST API 방식을 결정!
(REST API이용하기 공식문서)
https://developers.portone.io/docs/ko/auth/guide-1/bill/rest-api
(PortOne 예제 코드 깃 허브)
https://github.com/iamport/iamport-rest-client-java
순서 : 카드정보 입력받기 -> 카드 정보 추출하기 -> 빌링키 발급 요청 및 응답 처리
// iamport 결제 연동 allprojects { repositories { //... maven { url 'https://jitpack.io' } } } implementation 'com.github.iamport:iamport-rest-client-java:0.2.21'
빌링키 발급 컨트롤러
@ResponseBody @PostMapping("/issue-billing") public BaseResponse<IssueBillingRes> issueBilling(@RequestBody IssueBillingReq issueBillingReq){ try{ //int customerIdx = jwtService.getUserIdx(); IssueBillingRes issueBillingRes = paymentService.issueBilling(issueBillingReq); return new BaseResponse<>(issueBillingRes); }catch (BaseException baseException){ return new BaseResponse<>(baseException.getStatus()); } }
빌링키 발급 DTO
@Getter @Setter @NoArgsConstructor @AllArgsConstructor public class IssueBillingReq { private String cardNickName; private String pw6; private String card_number; private String expiry; private String birth; private String pwd_2digit; }
빌링키 발급 API (여기있는 pg파라미터 확인하기, 6번 KCP 비인증 결제 PG코드랑 다름)
https://developers.portone.io/docs/ko/api/billing-key-api/save-billing-key-api빌링키 삭제 API
https://developers.portone.io/docs/ko/api/billing-key-api/delete-billing-key-api
IamPort.java 인스턴스를 이용
- IamPort API 인가토큰 발행
- 빌링키에 매핑되는 Customer_uid 생성
- PortOne API에 빌링키 발행 요청
- 빌링키 발행 성공후 Customer_uid 서버에 저장
(Customer_uid, 카드 이름, 카드별칭, 카드 결제 비밀번호 6자리)@Transactional public IssueBillingRes issueBilling(IssueBillingReq issueBillingReq) throws BaseException { BillingCustomerData billingCustomerData = new BillingCustomerData( null, issueBillingReq.getCard_number(), issueBillingReq.getExpiry(), issueBillingReq.getBirth() ); // 1) iamPort API 인가 토큰 발행 -> API 사용하려면 반드시 필요한 값 AccessToken auth; try{ auth = iamportClient.getAuth().getResponse(); }catch (Exception e){ throw new BaseException(BILLING_API_ERROR); // iamport 서버 인가토큰 발행 실패 } // 2) 랜덤 Customer_uid (빌링키에 매핑되는) 생성 // 원래 있던 값을 재 사용해버리면 카드 매핑정보가 덮어씌워짐.. *** String newCustomerUid; try{ newCustomerUid = createNewCustomerUid(); // DB에 해당 빌링키 존재하는지 중복 확인 // EXIST 1이면 존재, 0이면 존재 안함 while(paymentDao.checkExsitBillingKey(newCustomerUid) == 1){ newCustomerUid = createNewCustomerUid(); } System.out.println("랜덤생성: " +newCustomerUid); }catch (Exception e){ throw new BaseException(BILLING_API_ERROR); // 랜덤 customer_uid(빌링키 매핑) 생성 오류 } // 3) 빌링키 발행 BillingKeyFoundation billingKeyFoundation; try{ billingCustomerData.setPg("kcp.T0000"); IamportResponse<BillingCustomer> billingCustomerInfo = iamportClient.postBillingCustomer( newCustomerUid, billingCustomerData); System.out.println(billingCustomerInfo.getResponse().toString()); billingKeyFoundation = new BillingKeyFoundation( billingCustomerInfo.getResponse().getCustomerUid(), // 빌링키 매핑 id billingCustomerInfo.getResponse().getCardName(), // 카드 이름 issueBillingReq.getCardNickName(), // 카드 별칭 issueBillingReq.getPw6()); // 비밀번호 6자리 }catch (Exception e){ throw new BaseException(BILLING_API_ERROR); // 빌링키 발행 실패 } // 4) 빌링키 서버 저장 try{ int billIdx = paymentDao.issueBilling(billingKeyFoundation); return new IssueBillingRes(billIdx); }catch (Exception e){ throw new BaseException(BILLING_API_ERROR); // 빌링키 앱 서버 DB저장 실패 } }
4-3-1) PG상점아이디 올바르지 않은 값
4-3-2) PG상점아이디 테스트 발급 후 요청 했지만 PG사 계약 안해서 API사용불가능
https://www.cosmosfarm.com/threads/document/23357
https://developers.portone.io/docs/ko/api/non-authenticated-payment-api/again-api
NHN KCP 설정
https://developers.portone.io/docs/ko/ready/2-pg/payment-gateway/nhn-kcp
NHN KCPO API 사용법
https://developers.portone.io/docs/ko/pg/payment-gateway/nhn-kcp