상품을 직접구매하거나 장바구니에 등록해서 한번에 구매하는 기능을 만들어보았는데 이번에는 결제 서비스를 적용시켜보려고한다. 결제서비스는 가장 유명하다는 '포트원'을 사용해서 진행해보려고한다.
먼저 PG사들을 모아서 간단하면서 한번에 제공해주는 서비스가 바로 포트원이다. 이때 PG란 Payment GateWay로 결제를 진행할때 카드사, 은행과 직접거래하는 대신에, 거래 및 결제를 대신 처리해주는 결제대행사 라고 생각하면된다.
우선 먼저 포트원 사이트로 이동해서 회원가입을 진행해준다.
회원가입을 진행했다면 시작하기버튼을 눌러서 해당 페이지로 이동
왼쪽의 메뉴에서 '결제 연동' 메뉴를 클릭해서 내 식별코드를 눌러서 REST API Key
, REST API Secret값을 확인한다.
키값을 확인했으면 결제대행사 설정 및 추가를 해주는데 이때 테스트로 KG이니시스를 진행한다
완료했다면 결제가 정상적으로 진행이 되는지를 알아보자
결제 시스템을 추가하려는 html에 코드를 추가해주면 된다.
(이 코드는 iamport에서 제공하는 코드이다.)
<script
type="text/javascript"
src="https://code.jquery.com/jquery-1.12.4.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.iamport.kr/js/iamport.payment-1.2.0.js"
></script>
<script>
var IMP = window.IMP;
IMP.init("impXXXXXXXX"); //이부분에 식별코드의 가맹점 식별코드 추가
function requestPay() {
IMP.request_pay(
{
pg: "html5_inicis", //KG이니시스 pg파라미터 값
pay_method: "card", //결제 방법
merchant_uid: "1234578",//주문번호
name: "테스트", //상품 명
amount: 1, //금액
buyer_email: "qkrtprjs@gmail.com",
buyer_name: "박세건",
buyer_tel: "010-4242-4242",
//buyer_addr: "서울특별시",
//buyer_postcode: "00000"
},
function (rsp) {
//rsp.imp_uid 값으로 결제 단건조회 API를 호출하여 결제결과를 판단합니다.
if (rsp.success) {
//서버 검증 요청 부분
} else {
alert("결제에 실패하였습니다. 에러 내용: " + rsp.error_msg);
}
}
);
}
</script>
<button onclick="requestPay()">결제하기</button>
결제가 정상적으로 진행이되도 다시한번 검증을 해야줘야한다! 이유는 결제가 정상적으로 이루어져도 사용자가 스크립트를 조작해서 금액을 변조할 수 있는 가능성이 있기때문입니다.
클라이언트 단에서 스크립트 조작을 원천적으로 막을 수 없기에 실제로 결제한 금액이 주문금액과 일치하는지 서버단에서 검증을 실시한다. 또한 IamPort에서도 후속 검증을 필수로 요청하고있다.
이때 사전 검증이란 결제창을 띄우기전에 포트원 서버로 정보를 전달해서 진행하는 검증이라고합니다.
imp_uid : 결제 고유번호
merchant_uid : 주문번호
postcode : 우편번호
currency : 화폐단위
paid_amount : 결제 금액
paid_at : 결제 시간
receipt_url : 영수증 url
이 정보를 rsp라는 변수에 담아서 가져오게된다
IMP.request_pay(
{
pg: "html5_inicis", //KG이니시스 pg파라미터 값
pay_method: "card", //결제 방법
merchant_uid: "1234572",//주문번호
name: "테스트", //상품 명
amount: 100, //금액
buyer_email: "qkrtprjs@gmail.com",
buyer_name: "박세건",
buyer_tel: "010-4242-4242",
//buyer_addr: "서울특별시",
//buyer_postcode: "00000"
},
function (rsp) {
//결제완료후 후속 검증 실행(주문금액과 일치하는지 확인)
console.log(rsp); //결제 금액이 들어있음
if (rsp.success) {
//서버 검증 요청 부분
let data = {
imp_uid: rsp.imp_uid, // 결제 고유번호
merchant_uid: rsp.merchant_uid, // 주문번호
amount: rsp.paid_amount
}
$.ajax({
url: '/payment/verification',
method: 'POST',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(data)
}).done(function (data) {
console.log(data);//주문 금액이 들어있음 // 위의 rsp.paid_amount 와 data.response.amount를 비교한후 로직 실행 (import 서버검증)
if (rsp.paid_amount == data.response.amount) {
alert("결제 및 결제검증완료");
} else {
alert("결제 실패");
}
});
}
//rsp.imp_uid 값으로 결제 단건조회 API를 호출하여 결제결과를 판단합니다.
else {
alert("결제에 실패하였습니다. 에러 내용: " + rsp.error_msg);
}
}
);
결제가 완료되었다면 후속 검증을 위한 ajax를 실행한다. data변수에는 결제 고유번호와 주문번호, 그리고 결제 금액을 보내준다. 결제 고유번호를 보내주고 IamPort에서 제공하는 라이브러리를 사용해서 고유번호를 통한 결제요청정보를 가져올 수 있다. 따라서 결제를 요청한 정보의 금액과 실제 결제 금액을 비교해서 맞는지 틀린지를 확인하는 것이다.
allprojects {
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com.github.iamport:iamport-rest-client-java:0.2.21' //IamPort 라이브러리 사용을 위한
추가하게되면 Iampor관련 라이브러리를 사용할 수 있게됩니다.
package com.qkrtprjs.happyexercise.dto;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Getter
@NoArgsConstructor
@ToString
public class PaymentVerificationDto {
private String imp_uid;
private String merchant_uid;
private String amount;
@Builder
public PaymentVerificationDto(String imp_uid) {
this.imp_uid = imp_uid;
}
}
@RestController
public class PaymentApiController {
private IamportClient iamportClient;
///IamportClient 객체 생성
public PaymentApiController() {
this.iamportClient = new IamportClient("4485726770034855", "13ir1LNySDUG95vc595hVx7lAHiGJzsINwV8w1LuthWzloDesrHkQvJhr849aK0dA9A8ASsvf1KDtlVd");
}
@PostMapping("/payment/verification")
private IamportResponse<Payment> paymentByImpUid(@RequestBody PaymentVerificationDto paymentVerificationDto) throws IamportResponseException, IOException {
System.out.println(paymentVerificationDto);
//paymentByImpUid를 사용하기 위해서는 토큰 발급이 필요하고, 토큰 발급을 하기 위해서는 위에 복사해 두었던 REST API 키 와 REST API secret 가 필요합니다.
return iamportClient.paymentByImpUid(paymentVerificationDto.getImp_uid());
}
}
IamportClient클래스의 paymentByImpUid() 함수를 사용해서 결제 요청 정보를 가져와야하는데 이 함수를 사용하기위해서는 토큰발급이 필요하고, 토큰 발급을 하기 위해서는 REST API키와 REST API SECRET가 필요하기때문에 IamportClient의 생성자를 이용해서 해당 값을 넣어준다.
해당 값들은 이전에 회원가입 진행하면서 확인할 수 있다.
리턴값의 response에 관련정보들이 들어있는것을 확인할 수 있다.
if (rsp.paid_amount == data.response.amount) {
alert("결제 및 결제검증완료");
} else {
alert("결제 실패");
}
정상적으로 결제가 완료되었고 검증이 완료되었음을 확인할 수 있습니다.
검증이 완료되지 않는경우를 테스트 하려면 스크립트 공격을 사용해야하는데 아직 잘 알지못해서 넘어가고 후에 스크립트를 건들여서 테스트 해보기로하자