나만의 프로젝트 배포하기 14일차

박세건·2023년 9월 27일
0

개인 프로젝트

목록 보기
14/15

결제 서비스 적용시켜보기

상품을 직접구매하거나 장바구니에 등록해서 한번에 구매하는 기능을 만들어보았는데 이번에는 결제 서비스를 적용시켜보려고한다. 결제서비스는 가장 유명하다는 '포트원'을 사용해서 진행해보려고한다.

PG?

먼저 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에서도 후속 검증을 필수로 요청하고있다.

이때 사전 검증이란 결제창을 띄우기전에 포트원 서버로 정보를 전달해서 진행하는 검증이라고합니다.

  • 사후 검증을 실행할때에 아임포트의 API문서를 참고해서 진행해도 되지만 토큰을 사용한다는 점에서 복잡하기때문에 아임포트에서 제공하는 자바용 모듈을 사용하자!

결제 완료시에 반환 데이터

imp_uid : 결제 고유번호
merchant_uid : 주문번호
postcode : 우편번호
currency : 화폐단위
paid_amount : 결제 금액
paid_at : 결제 시간
receipt_url : 영수증 url

이 정보를 rsp라는 변수에 담아서 가져오게된다

  • 검증을 위한 rquestPay() 코드 수정
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에서 제공하는 라이브러리를 사용해서 고유번호를 통한 결제요청정보를 가져올 수 있다. 따라서 결제를 요청한 정보의 금액과 실제 결제 금액을 비교해서 맞는지 틀린지를 확인하는 것이다.

  • IamPor에서 제공하는 라이브러리를 사용하기위한 build.gradle 수정
allprojects {
	repositories {
		mavenCentral()
		maven { url 'https://jitpack.io' }
	}
}




dependencies {
	implementation 'com.github.iamport:iamport-rest-client-java:0.2.21'	//IamPort 라이브러리 사용을 위한

추가하게되면 Iampor관련 라이브러리를 사용할 수 있게됩니다.

  • ajax로 넘겨준 데이터들과 연관되는 dto
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에 관련정보들이 들어있는것을 확인할 수 있다.

  • 다시 스크립트 구문으로 돌아와서 두개의 amount를 비교한다.
  if (rsp.paid_amount == data.response.amount) {
                                alert("결제 및 결제검증완료");
                            } else {
                                alert("결제 실패");
                            }

정상적으로 결제가 완료되었고 검증이 완료되었음을 확인할 수 있습니다.
검증이 완료되지 않는경우를 테스트 하려면 스크립트 공격을 사용해야하는데 아직 잘 알지못해서 넘어가고 후에 스크립트를 건들여서 테스트 해보기로하자

출처 Blackarea님의 벨로그

profile
멋있는 사람 - 일단 하자

0개의 댓글