※ 이 사이트는 Internet Explorer 10 이하 버전은 지원하지 않습니다. 최신 브라우저로 업데이트해 주세요.
빌링 연동
스마트로페이 결제모듈 연동을 위한 가이드입니다.
- 해당 매뉴얼의 Parameter 들은 가맹점에 통보 없이 응답값이 추가 될 수 있습니다. 응답값 추가도 고려하여 개발 진행하시길 권장합니다 . - Test 연동시 체크 카드는 사용자제 부탁드립니다.체크 카드 결제시 Test 계에서는 당일 전체 취소만 가능 합니다 (부분취소 지원 불가) - 빌링키 발급 시 해외카드는 지원되지 않습니다.(국내카드만 등록 가능) - 스마트로 사업자번호로 제공된 테스트 Mid는 국민카드(카카오뱅크), 하나카드 결제가 불가합니다.
빌링연동(SS-Pay)
Online 신용카드 빌링 스마트로페이의 Online 신용카드 정기과금(빌링)서비스 연동에 대한 안내입니다. * 스마트로페이의 응답은 POST입니다. 연동 시 참고해 주세요.
스마트로페이 SERVER IP
스마트로페이 서비스 IP 정보입니다.
구분
IP
비고
테스트
211.193.35.11
STG
운영 - 결제
211.193.35.20
운영 - 재통보
211.193.35.216 211.193.35.217
재통보 서비스 사용시
OPTIONS빌링키 발급 정책
가맹점 정책에 맞는 옵션을 선택하여 영업담당자에게 요청 주시길 바랍니다.
발급 정책
옵션
본인인증 사용여부
미사용
/
휴대폰 인증 - 본인인증 미사용 옵션 시 타인의 카드 정보를 등록하여 결제 가능한 점 유의해주시길 바랍니다.
Bill-Key 발급 정책
회원 기준 1개 발급
/
회원 기준 다수개 발급 - 회원 기준 1개 발급 설정의 경우 미삭제 신규 등록 설정은 불가합니다.
동일 카드 등록여부
거절
/
기등록 빌링키 정보 전달
/
삭제 후 신규 등록
/
미삭제 신규 등록
추가 카드 등록여부
거절
/
삭제 후 신규 등록
/
미삭제 신규 등록
(참고) 옵션 선택 자세히보기
CASE1) 회원ID당 본인소유의 카드 1개의 빌링키만 발급 희망 시 선택 옵션
(필수)본인 인증 : 휴대폰 인증
(필수)Bill-Key 발급 정책 : 회원기준 1개 발급
(선택가능)동일 카드 등록여부 : 거절 or 기등록 빌링키 정보 전달 or 삭제 후 신규 등록 (*거절 옵션의 경우 최조 빌링키 발급 이후 동일카드 등록 불가)
(선택가능)추가 카드 등록여부 : 거절 or 삭제 후 신규 등록 (*거절 옵션의 경우 최조 빌링키 발급 이후 카드 등록 불가)
CASE2) 회원ID당 본인소유의 카드 다수개 빌링키 발급 가능 옵션
(필수)본인 인증 : 휴대폰 인증
(필수)Bill-Key 발급 정책 : 회원기준 다수개 발급
(선택가능)동일 카드 등록여부 : 미삭제 신규 등록
(선택가능)추가 카드 등록여부 : 미삭제 신규 등록
CASE3) 회원ID당 다수개 빌링키 발급 가능 옵션(소유주 무관)
(필수)본인 인증 : 미사용
(필수)Bill-Key 발급 정책 : 회원기준 다수개 발급
(선택가능)동일 카드 등록여부 : 미삭제 신규 등록
(선택가능)추가 카드 등록여부 : 미삭제 신규 등록
String Mid = ""; // 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
String MerchantKey = ""; // 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
String EdiDate = getyyyyMMddHHmmss();
String EncryptData = encodeSHA256Base64(EdiDate + Mid + Moid + "SMARTRO!@#");
String today = getyyyyMMddHHmm(); // 현재일자. 캐시방지용으로 사용
/* SHA256 암호화 */
public static final String encodeSHA256Base64(String strPW) {
String passACL = null;
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (Exception e) {
e.printStackTrace();
}
md.update(strPW.getBytes());
byte[] raw = md.digest();
byte[] encodedBytes = Base64.encodeBase64(raw);
passACL = new String(encodedBytes);
return passACL;
}
/* 현재일자 */
public static final String getyyyyMMddHHmmss() {
SimpleDateFormat yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss");
return yyyyMMddHHmmss.format(new Date());
}
/* 현재일자 */
public static final String getyyyyMMddHHmm() {
SimpleDateFormat yyyyMMddHHmm = new SimpleDateFormat("yyyyMMddHHmm");
return yyyyMMddHHmm.format(new Date());
}
$Mid = ""; // 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
$MerchantKey = ""; // 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
$EdiDate = date("YmdHis");
$EncryptData = base64_encode(hash('sha256', $EdiDate.$Mid.$Moid."SMARTRO!@#", true));
$today = date("YmdHi"); // 현재일자. 캐시방지용으로 사용
Mid = "" ' 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
MerchantKey = "" ' 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
EdiDate = Year(Now()) & right("0"&Month(Now()),2) & right("0"&Day(Now()),2) & right("0"&Hour(Now()),2) & right("0"&Minute(Now()),2) & right("0"&Second(Now()),2)
EncryptData = CryptoUtil.Sha256Encrypt(EdiDate & Mid & Moid & "SMARTRO!@#"))
today = Year(Now()) & right("0"&Month(Now()),2) & right("0"&Day(Now()),2) & right("0"&Hour(Now()),2) & right("0"&Minute(Now()),2) ' 현재일자. 캐시방지용으로 사용
// DLL 암호화 소스
using System;
using System.EnterpriseServices;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
namespace SmartropayLib
{
public class CryptoUtil : ServicedComponent
{
///
/// SHA256 암호화
///
/// 문자열
/// 암호화 문자열
public string Sha256Encrypt(string text)
{
SHA256Managed sha256Managed = new SHA256Managed();
byte[] encryptBytes = sha256Managed.ComputeHash(Encoding.UTF8.GetBytes(text));
return Convert.ToBase64String(encryptBytes);
}
}
}
const crypto = require('crypto');
// 테스트 MID 및 MerchantKey 설정 (운영 전환 시 실제 값 사용)
const Mid = ""; // 발급받은 테스트 Mid 설정
const MerchantKey = ""; // 발급받은 테스트 상점키 설정
const Moid = ""; // 주문번호 (예시)
const EdiDate = getyyyyMMddHHmmss(); // 현재일자
const EncryptData = encodeSHA256Base64(EdiDate + Mid + Moid + "SMARTRO!@#");
const today = getyyyyMMddHHmm(); // 현재일자 (캐시 방지용)
// SHA256 암호화 + Base64 인코딩
function encodeSHA256Base64(strPW) {
const hash = crypto.createHash('sha256');
hash.update(strPW);
return Buffer.from(hash.digest()).toString('base64'); // SHA256 결과를 Base64로 인코딩
}
// 현재일자 (yyyyMMddHHmmss 형식)
function getyyyyMMddHHmmss() {
const now = new Date();
return now.toISOString().replace(/[-T:Z.]/g, '').slice(0, 14); // 'YYYYMMDDHHMMSS' 형식으로 변환
}
// 현재일자 (yyyyMMddHHmm 형식)
function getyyyyMMddHHmm() {
const now = new Date();
return now.toISOString().replace(/[-T:Z.]/g, '').slice(0, 12); // 'YYYYMMDDHHMM' 형식으로 변환
}
// 테스트 실행
console.log("EncryptData:", EncryptData);
console.log("EdiDate:", EdiDate);
console.log("today:", today);
- Python 모듈 소스의 경우 Django(v.5.0.7)를 기반으로 작성되었습니다.
import hashlib
import base64
import datetime
Mid = "" # 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
MerchantKey = "" # 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
EdiDate = "" # EdiDate
today = "" # 현재일자, 캐시방지용으로 사용
# EdiDate 생성
def getyyyyMMddHHmmss():
return datetime.datetime.now().strftime("%Y%m%d%H%M%S")
EdiDate = getyyyyMMddHHmmss()
# today 생성
def getyyyyMMddHHmm():
return datetime.datetime.now().strftime("%Y%m%d%H%M")
today = getyyyyMMddHHmm()
# EncryptData 생성
def encodeSHA256Base64(strPW):
sha256_object = hashlib.sha256()
sha256_object.update(strPW.encode())
return base64.b64encode(sha256_object.digest()).decode("utf-8")
EncryptData = encodeSHA256Base64(EdiDate + Mid + Moid + "SMARTRO!@#")
STEP 1-2Form 데이터 설정
·JSP
SmartroPAY 연동가이드
import { useEffect } from 'react';
function Pay() {
// PC/Mobile 구분하여 도메인 변경 필요
// PC 환경에서 호출시 https://tpay.smartropay.co.kr/asset/js/SmartroPAY-1.0.min.js?version=현재일자
// Mobile 환경에서 호출시 https://tmpay.smartropay.co.kr/asset/js/SmartroPAY-1.0.min.js?version=현재일자
// 운영 전환 시 도메인 변경
// PC : tpay.smartropay.co.kr -> pay.smartropay.co.kr
// Mobile : tmpay.smartropay.co.kr -> mpay.smartropay.co.kr
// script 캐시방지를 위해 ?version=today를 추가 ex) SmartroPAY-1.0.min.js?version=20230101
useEffect(() => {
const script = document.createElement('script');
script.src = `https://tpay.smartropay.co.kr/asset/js/SmartroPAY-1.0.min.js?version=&{ today }`;
script.type = 'text/javascript';
document.head.appendChild(script);
return () => {
document.head.removeChild(script);
}
}
, []);
// 스마트로 페이 응답은 POST로 응답됩니다.
// POST 응답을 받을 수 있는 서버 url을 넣어주세요.
const ReturnUrl = "";
const goPay = () => {
window.smartropay.init({
mode : 'STG', // STG: 테스트, REAL: 운영(운영서버 전환 시 변경 필수!)
actionUri : '/ssb/interface.do'
});
// 스마트로페이 빌링키 발급요청
window.smartropay.payment({
FormId : 'tranMgr' // 폼ID
});
}
return(
<>
>
);
}
export default Pay;
STEP 1-3발급 결과 받기
·JSP
String tempVerifyValue = null;
boolean result = false;
String BillTokenKey = request.getParameter("BillTokenKey");
String Mid = request.getParameter("Mid");
String DisplayCardNo = request.getParameter("DisplayCardNo");
String ResultCode = request.getParameter("ResultCode");
String VerifyValue = request.getParameter("VerifyValue");
try {
String merchantKey = ""; // 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
String mKey = merchantKey.substring(0,32);
BillTokenKey = AESDecode(BillTokenKey, mKey); // AESDecode 후 가맹점DB에 빌링키 저장
String tempVerifyValueString = Mid + BillTokenKey + DisplayCardNo + ResultCode + "SMARTRO!@#";
tempVerifyValue = encodeSHA256Base64(tempVerifyValueString);
result = tempVerifyValue.equals(VerifyValue) ? true : false;
}catch(Exception e) {
e.printStackTrace();
}
// Decode 함수
public static byte[] ivBytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
public static String AESDecode(String str, String key) throws Exception {
//byte[] textBytes = Base64.decodeBase64(str.getBytes());
String result = null;
byte[] textBytes = Base64.decodeBase64(str);
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
SecretKeySpec newKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
result = new String(cipher.doFinal(textBytes), "UTF-8");
return result;
}
getMessage());
}
// 결과 출력 (필요에 따라 수정)
echo "BillTokenKey: " . $BillTokenKey . "
복호화된 빌링키 전달 빌링키는 선택 조건으로 빌링키 전달 시 요청한 빌링키 정보만 조회
빌링키 전달하지 않은 경우 MallUserId에 발급된 빌링키 리스트 조회
파라미터
항목명
길이(char)
설명
SspMallId
결제MALL ID
10
MallUserId
회원사 고객 ID
20
ResultCode
결과코드
10
0000 : success
PR01 : 멤버 정보 미존재
PA50 : 발급정보없음
* 그 외 응답 - 통합코드 조회 참고
ResultMsg
결과메시지
80
ResultData
*ResultCode=0000 시 응답
빌링키 상세 조회리스트
가변
하단 응답 예시 참고
파라미터
항목명
길이(char)
설명
RegMid
등록 Mid
10
BillTokenKey
고정식토큰(빌링키)
50
IssuerCardCd
발급사 코드
2
IssuerCardNm
발급사명
10
DisplayCardNo
표시용 카드번호
20
마스킹되어 전달
CardExpire
빌링키 유효기간
4
YYMM
실제 카드 유효기간 -2개월로 응답
RegDt
빌링키 등록 일자
8
YYYYMMDD
STEP 1빌링키 조회 파라미터 설정 및 UrlCall 조회 요청하기
·JSP
String url = "https://tapproval.smartropay.co.kr/payment/approval/billKeyInquiry.do"; // 테스트
// String url = "https://approval.smartropay.co.kr/payment/approval/billKeyInquiry.do"; // 운영
JSONObject body = new JSONObject();
JSONObject paramData = new JSONObject();
String merchantKey = ""; // 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
String Mid = ""; // 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
String SspMallId = "SMTSSPAY0p"; // 테스트용 SspMallId
String MallUserId = ""; // 회원사 고객 ID
String BillTokenKey = ""; // 빌링키 발급을 통해 생성된 키
// 요청 파라미터 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
paramData.put("SspMallId", SspMallId);
paramData.put("MallUserId", MallUserId);
paramData.put("BillTokenKey", BillTokenKey);
$url = "https://tapproval.smartropay.co.kr/payment/approval/billKeyInquiry.do"; // 테스트
//$url = "https://approval.smartropay.co.kr/payment/approval/billKeyInquiry.do"; // 운영
$MerchantKey = ""; // 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
$Mid = ""; // 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
$SspMallId = "SMTSSPAY0p"; // 테스트용 SspMallId
$MallUserId = ""; // 회원사 고객 ID
$BillTokenKey = ""; // 발급받은 빌링키
$paramData = array(
'SspMallId' => $SspMallId,
'MallUserId' => $MallUserId,
'BillTokenKey' => $BillTokenKey
);
url = "https://tapproval.smartropay.co.kr/payment/approval/billKeyInquiry.do" ' 테스트
'url = "https://approval.smartropay.co.kr/payment/approval/billKeyInquiry.do" ' 운영
merchantKey = "" ' 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
Mid = "" ' 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
SspMallId = "SMTSSPAY0p" ' 테스트용 SspMallId
MallUserId = ""; ' 회원사 고객 ID
BillTokenKey = "" ' 발급받은 빌링키
Set paramData = jsObject()
paramData("SspMallId") = SspMallId
paramData("MallUserId") = MallUserId
paramData("BillTokenKey") = BillTokenKey
const axios = require('axios');
const crypto = require('crypto');
const domainUrl = 'https://tapproval.smartropay.co.kr/'; // 테스트 URL
// const domainUrl = 'https://approval.smartropay.co.kr/'; // 운영 URL
// AES256 암호화 함수
function AES256Encode(data, key) {
const iv = Buffer.alloc(16, 0);
const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv);
let encrypted = cipher.update(data, 'utf8', 'base64');
encrypted += cipher.final('base64');
return encrypted;
}
async function inquiry() {
const restRequestUrl = domainUrl + 'payment/approval/billKeyInquiry.do';
const merchantKey = ''; // 발급받은 테스트 상점키 설정
const Mid = ''; // 발급받은 테스트 Mid 설정
const SspMallId = ''; // 테스트용 SspMallId
const MallUserId = ''; // 회원사 고객 ID
const BillTokenKey = ''; // 빌링키 발급을 통해 생성된 키
const body = {
SspMallId: SspMallId,
MallUserId: MallUserId,
BillTokenKey: BillTokenKey
};
// JSON 데이터 AES256 암호화
const sendObject = {
EncData: AES256Encode(JSON.stringify(body), merchantKey.substring(0, 32)),
Mid: Mid
};
// .... STEP2 요청 및 결과 받기
from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
import json
import requests
import base64
from Cryptodome.Cipher import AES
from Cryptodome import Random
@csrf_exempt
def inquiry(request):
# 빌링키 조회 요청
# 운영 : https://approval.smartropay.co.kr/payment/approval/billKeyInquiry.do
# 테스트 : https://tapproval.smartropay.co.kr/payment/approval/billKeyInquiry.do
url = 'https://tapproval.smartropay.co.kr/payment/approval/billKeyInquiry.do'
Mid = "" # 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
MerchantKey = "" # 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
SspMallId = "" # 발급받은 SspMallId
MallUserId = "" # MallUserId
BillTokenKey = "" # 빌링키 발급을 통해 생성된 키
# 요청 파라미터 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
paramData = {
'SspMallId' : SspMallId,
'MallUserId' : MallUserId,
'BillTokenKey' : BillTokenKey
}
# .... STEP2 요청 및 결과 받기
STEP 2빌링키 조회 결과 받기
·JSP
// json 데이터 AES256 암호화
try {
body.put("EncData", AES256Cipher.AES_Encode(paramData.toString(), merchantKey.substring(0,32)));
body.put("Mid", Mid);
} catch(Exception e){
e.printStackTrace();
}
HashMap<String, Object> result = callApi(body, url);
public HashMap<String, Object> callApi(JSONObject json, String callUrl) {
StringBuilder responseBody = null;
HashMap<String, Object> result = new HashMap<>();
// http urlCall 승인 요청 및 TrAuthKey 유효성 검증
int connectTimeout = 1000;
int readTimeout = 10000; // 가맹점에 맞게 TimeOut 조절
URL url = null;
HttpsURLConnection connection = null;
try {
SSLContext sslCtx = SSLContext.getInstance("TLSv1.2");
sslCtx.init(null, null, new SecureRandom());
url = new URL(callUrl);
System.out.println(" url " + url.toString());
connection = (HttpsURLConnection)url.openConnection();
connection.setSSLSocketFactory(sslCtx.getSocketFactory());
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setConnectTimeout(connectTimeout);
connection.setReadTimeout(readTimeout);
OutputStreamWriter osw = new OutputStreamWriter(new BufferedOutputStream(connection.getOutputStream()) , "utf-8" );
char[] bytes = json.toString().toCharArray();
osw.write(bytes,0,bytes.length);
osw.flush();
osw.close();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
String line = null;
responseBody = new StringBuilder();
while ((line = br.readLine()) != null) {
System.out.println(" response " + line);
responseBody.append(line);
}
br.close();
// 결제결과
result = new ObjectMapper().readValue(responseBody.toString(), HashMap.class);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
0000 : success
PR01 : 멤버 정보 미존재
* 그 외 응답 - 통합코드 조회 참고
ResultMsg
결과메시지
80
RegMid
등록 Mid
10
회원 등록 시 Mid
BuyerName
구매자명
30
마스킹되어 응답
두자릿수: 첫글자 마스킹 (예) *가
세자릿수 이상 : 첫글자 마지막 글자 외 마스킹 (예) 홍*동 구매자명 미등록인 경우 빈값으로 응답
BuyerTel
구매자휴대폰번호
40
중간 마스킹 (예) 010-****-1111 구매자휴대폰번호 미등록인 경우 빈값으로 응답
RegDt
회원 등록 일자
8
YYYYMMDD
STEP 1SS-PAY 회원 조회 파라미터 설정 및 UrlCall 조회 요청하기
·JSP
String url = "https://tapproval.smartropay.co.kr/payment/approval/mallUserIdInquiry.do"; // 테스트
// String url = "https://approval.smartropay.co.kr/payment/approval/mallUserIdInquiry.do"; // 운영
JSONObject body = new JSONObject();
JSONObject paramData = new JSONObject();
String merchantKey = ""; // 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
String Mid = ""; // 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
String SspMallId = "SMTSSPAY0p"; // 테스트용 SspMallId
String MallUserId = ""; // 회원사 고객 ID
// 요청 파라미터 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
paramData.put("SspMallId", SspMallId);
paramData.put("MallUserId", MallUserId);
$url = "https://tapproval.smartropay.co.kr/payment/approval/mallUserIdInquiry.do"; // 테스트
//$url = "https://approval.smartropay.co.kr/payment/approval/mallUserIdInquiry.do"; // 운영
$MerchantKey = ""; // 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
$Mid = ""; // 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
$SspMallId = "SMTSSPAY0p"; // 테스트용 SspMallId
$MallUserId = ""; // 회원사 고객 ID
$paramData = array(
'SspMallId' => $SspMallId,
'MallUserId' => $MallUserId
);
url = "https://tapproval.smartropay.co.kr/payment/approval/mallUserIdInquiry.do" ' 테스트
'url = "https://approval.smartropay.co.kr/payment/approval/mallUserIdInquiry.do" ' 운영
merchantKey = "" ' 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
Mid = "" ' 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
SspMallId = "SMTSSPAY0p" ' 테스트용 SspMallId
MallUserId = ""; ' 회원사 고객 ID
Set paramData = jsObject()
paramData("SspMallId") = SspMallId
paramData("MallUserId") = MallUserId
const axios = require('axios');
const crypto = require('crypto');
const domainUrl = 'https://tapproval.smartropay.co.kr/'; // 테스트 URL
// const domainUrl = 'https://approval.smartropay.co.kr/'; // 운영 URL
// AES256 암호화 함수
function AES256Encode(data, key) {
const iv = Buffer.alloc(16, 0);
const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv);
let encrypted = cipher.update(data, 'utf8', 'base64');
encrypted += cipher.final('base64');
return encrypted;
}
async function inquiry() {
const restRequestUrl = domainUrl + 'payment/approval/mallUserIdInquiry.do';
const merchantKey = ''; // 발급받은 테스트 상점키 설정
const Mid = ''; // 발급받은 테스트 Mid 설정
const SspMallId = ''; // 테스트용 SspMallId
const MallUserId = ''; // 회원사 고객 ID
const body = {
SspMallId: SspMallId,
MallUserId: MallUserId
};
// JSON 데이터 AES256 암호화
const sendObject = {
EncData: AES256Encode(JSON.stringify(body), merchantKey.substring(0, 32)),
Mid: Mid
};
// .... STEP2 요청 및 결과 받기
from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
import json
import requests
import base64
from Cryptodome.Cipher import AES
from Cryptodome import Random
@csrf_exempt
def inquiry(request):
# 회원 조회 요청
# 운영 : https://approval.smartropay.co.kr/payment/approval/mallUserIdInquiry.do
# 테스트 : https://tapproval.smartropay.co.kr/payment/approval/mallUserIdInquiry.do
url = 'https://tapproval.smartropay.co.kr/payment/approval/mallUserIdInquiry.do'
Mid = "" # 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
MerchantKey = "" # 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
SspMallId = "" # 발급받은 SspMallId
MallUserId = "" # MallUserId
# 요청 파라미터 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
paramData = {
'SspMallId' : SspMallId,
'MallUserId' : MallUserId
}
# .... STEP2 요청 및 결과 받기
STEP 2빌링키 조회 결과 받기
·JSP
// json 데이터 AES256 암호화
try {
body.put("EncData", AES256Cipher.AES_Encode(paramData.toString(), merchantKey.substring(0,32)));
body.put("Mid", Mid);
} catch(Exception e){
e.printStackTrace();
}
HashMap<String, Object> result = callApi(body, url);
public HashMap<String, Object> callApi(JSONObject json, String callUrl) {
StringBuilder responseBody = null;
HashMap<String, Object> result = new HashMap<>();
// http urlCall 승인 요청 및 TrAuthKey 유효성 검증
int connectTimeout = 1000;
int readTimeout = 10000; // 가맹점에 맞게 TimeOut 조절
URL url = null;
HttpsURLConnection connection = null;
try {
SSLContext sslCtx = SSLContext.getInstance("TLSv1.2");
sslCtx.init(null, null, new SecureRandom());
url = new URL(callUrl);
System.out.println(" url " + url.toString());
connection = (HttpsURLConnection)url.openConnection();
connection.setSSLSocketFactory(sslCtx.getSocketFactory());
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setConnectTimeout(connectTimeout);
connection.setReadTimeout(readTimeout);
OutputStreamWriter osw = new OutputStreamWriter(new BufferedOutputStream(connection.getOutputStream()) , "utf-8" );
char[] bytes = json.toString().toCharArray();
osw.write(bytes,0,bytes.length);
osw.flush();
osw.close();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
String line = null;
responseBody = new StringBuilder();
while ((line = br.readLine()) != null) {
System.out.println(" response " + line);
responseBody.append(line);
}
br.close();
// 결제결과
result = new ObjectMapper().readValue(responseBody.toString(), HashMap.class);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
- 위의 계산방식은 일반 연동을 사용하며 부가세를 직접 계산하는 가맹점일 경우에 한합니다. - 비과세 가맹점인 경우
비과세금액(TaxFreeAmt)이 총금액(Amt)과 일치해야 하며 과세(TaxAmt)와 부가세(VatAmt)는 0 으로 세팅
- 간편 연동을 사용하거나 직접 계산을 하지 않는 경우, 비과세 가맹점에는 해당되지 않습니다. ※ 부가세 계산방식을 자동 계산 방식으로 변경 희망하시는 경우, 영업 담당자에게 문의 부탁드립니다.
(참고) AES256 암호화 중 예외 발생 시 조치사항
'java.security.InvalidKeyException: Illegal key size' 라는 예외가 발생했을 경우 아래와 같이 해결해 주세요.
1. 현재 사용중인 Java 버전에 맞춰 Unlimited Strength 정책 파일을 다운받습니다.
2. 다운받은 파일의 local_policy.jar, US_export_policy.jar 파일을 <JAVA_HOME>/jre/lib/security/ 폴더로 옮겨 기존 정책을 덮어씌웁니다.
그러면 JCE로 사용 가능한 모든 암호화의 키 길이 제한이 해제됩니다.
※ 8u151 Release Notes에서는 해당 버전부터 별도의 다운로드 없이 Unlimited Strength 정책을 설정할 수 있게 추가 번들이 같이 제공됩니다.
해당 버전에서 정책 파일은 <JAVA_HOME>/jre/lib/security/policy 경로에 limited와 unlimited 폴더로 구성되며,
unlimited 설정은 <JAVA_HOME>/jre/lib/security/java.security 파일을 열어
crypto.policy=unlimited 부분의 주석 처리를 지워주면 제한 해제된 정책을 사용할 수 있습니다.
※ 변경된 기본 정책
2018년 1월 업데이트된 Java8u161 Release Notes에 따르면, Java8u161 버전부터는 JCE 기본 정책이 unlimited이며,
길이를 제한하고 싶다면 crypto.policy=unlimited 부분을 주석처리하면 됩니다.
Unlimited를 기본으로 사용하는 Java 버전은 'JDK-8170157 : Enable unlimited cryptographic policy by default in Oracle JDK builds'에서 확인할 수 있습니다.
(추가) 가상키패드 지원사양
서비스 이용시 정상적인 가상키패드 이용을 위한 지원 사양으로, 아래 명시된 사양보다 이전 버전인 경우 정상적으로 이용이 불가할 수 있습니다.
Web Browser : Internet Explorer 11이상, Internet Explorer Edge 25이상, Chrome 32 이상, Safari 7 이상 (Windows 버전 제외)
Android : 4.0 이상 (공식지원 브라우저 : Chrome, 삼성브라우저)
iOS : 8.0 이상 (공식지원 브라우저 : Chrome, Safari)