修改歷程
版本 | 異動日期 | 修訂內容 | 位置 |
---|---|---|---|
1.0 | 2023.02.17 | 新版文件 | |
1.0.1 | 2023.06.27 | 新增收款帳戶設定與企業指定放行人通知 | 收款帳戶設定通知與企業指定放行人通知 |
Pay Off設計概要
安全性設計
Pay Off 是為滿足企業撥付獎金,供應商貨款等自動撥款需求而設計: 我們提供介接方式是透過https連線,只接受POST方式傳送交易資料。 本機制可以讓企業將付款機制整合到企業內部ERP系統,以企業既有放行權限即可完成放款。
Pay Off 目前提供之服務與格式
有7支API,各功能說明如下::
(1)收款帳戶設定:企業對mypay發動,由mypay驗證收款人身份綁定銀行帳戶,僅新收款人需要,以減少在網路傳遞個人相關資料,增強安全性。
(2)企業指定放行人:企業對mypay發動,由企業指定的撥款放行人,mypay驗證放行人身份,由放行人自行設定交易密碼。
(3)建立撥款批次:企業對mypay發動,將整批撥款檔上傳MYPAY,發動批次撥款,預先告知系統指定收款人撥放金額。
(4)批次補撥款:該撥款批次中有部分撥款失敗或放行人退件,可再發動將未撥款筆撥付。
(5)放行交易:企業指定的放行人,進行撥款放行動作。
(6)查詢交易:查詢指定批次撥款的最新狀態。
(7)忘記交易密碼:撥款放行人若要變更放款密碼。
我們提供介接方式是透過https連線,只接受POST方式傳送交易資料。
介接網址
經銷商模式
位置 | API介接網址 | 備註 |
---|---|---|
測試區 | https://auth.usecase.cc/api/agent | |
正式區 | https://auth.mypay.tw/api/agent | 限定Ip連線 |
資料加密方式
AES 256編碼 + base64編碼(附錄四資料加密方式)
加密金鑰
金鑰會透過mail發送,也可從管理後台取得
文字編碼
一律使用UTF-8相容編碼
收款帳戶設定
<?php
/**
* 經銷商串接-收款帳戶設定
*/
final class AgentPayoffReneficiary
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://auth.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['user_data'] = [
'user_id' => 'payee',
'bank_code' => '426',
'bank_branch_code' => '0000',
'bank_account_number' => '1100000000003001'
];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'ocp',
'cmd' => 'api/payoffbeneficiary'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentPayoffReneficiary = new AgentPayoffReneficiary();
$AgentPayoffReneficiary->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-收款帳戶設定
/// </summary>
public class AgentPayoffReneficiary {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://auth.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentPayoffReneficiary simulator = new AgentPayoffReneficiary();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic userData = new ExpandoObject();
userData.user_id = "payee";
userData.bank_code = "426";
userData.bank_branch_code = "0000";
userData.bank_account_number = "1100000000003001";
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.user_data = userData;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "ocp";
rawData.cmd = "api/payoffbeneficiary";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-收款帳戶設定
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentPayoffReneficiary {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://auth.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentPayoffReneficiary simulator = new AgentPayoffReneficiary();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> userData = new HashMap<Object, Object>();
userData.put("user_id", "payee");
userData.put("bank_code", "426");
userData.put("bank_branch_code", "0000");
userData.put("bank_account_number", "1100000000003001");
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("user_data", userData);
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "ocp");
rawData.put("cmd", "api/payoffbeneficiary");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-收款帳戶設定
*/
function AgentPayoffReneficiary() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://auth.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentPayoffReneficiary.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
user_data: {
'user_id': "payee",
'bank_code': "426",
'bank_branch_code': "0000",
'bank_account_number': "1100000000003001"
},
};
};
/**
* 取得服務位置
*/
AgentPayoffReneficiary.prototype.getService = function () {
return {
service_name: "ocp",
cmd: "api/payoffbeneficiary"
};
};
/**
* AES 256 加密
*/
AgentPayoffReneficiary.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentPayoffReneficiary.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentPayoffReneficiary.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentPayoffReneficiary.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentPayoffReneficiary = new AgentPayoffReneficiary();
AgentPayoffReneficiary.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-收款帳戶設定
"""
class AgentPayoffReneficiary:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://auth.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'user_data': {
'user_id': "payee",
'bank_code': "426",
'bank_branch_code': "0000",
'bank_account_number': "1100000000003001"
},
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'ocp',
'cmd': 'api/payoffbeneficiary'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentPayoffReneficiary = AgentPayoffReneficiary()
AgentPayoffReneficiary.run()
回傳 JSON 結構如下:
{
"url": "https:\/\/ocpwallet.usecase.cc\/open\/778b3f2e08c2485fabad5f8090546af4",
"code": "B200",
"msg": "執行成功"
}
撥款前須要先讓收款人設定『收款人資訊』。透過此API,可以讓收款人登入Ocp設定收款銀行帳戶。
經銷商『收款帳戶設定』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "ocp", "cmd": "api\/payoffbeneficiary"} JSON格式,AES256加密資料 |
encry_data | text | 『收款帳戶設定』欄位參考 JSON格式,AES256加密資料 |
『收款帳戶設定』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string | 特約商店商務代號 | 必填 |
user_data | object | 收款人資訊 | 必填 『收款人資訊』欄位參考 |
success_returl | string | 設定成功導頁連結 | |
failure_returl | string | 設定失敗導頁連結 | |
homepage_url | string | 返回首頁連結 | |
return_url | string | 收款帳戶設定完成後結果通知網址 |
『收款帳戶設定』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『Pay Off 執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
url | string | 設定網址 | |
uid | string | UID(完成設定回報通知時驗證用) | |
key | string | 驗証碼(完成設定回報通知時驗證用) |
『收款帳戶設定通知』回報欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | UID | |
key | string | 驗証碼 | |
code | string | 狀態碼 | 『處理狀態碼』值參考 |
msg | string | 狀態碼說明 | |
finished_date | string | 收款帳戶設定完成時間(格式:yyyyMMddHHmmss) | |
store_uid | string | 特約商店商務代號 | |
user_id | string | 收款人帳號 |
企業指定放行人
<?php
/**
* 經銷商串接-企業指定放行人
*/
final class AgentPayoffReleaser
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://auth.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['user_data'] = [
'user_id' => 'phper'
];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/payoffreleaser'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentPayoffReleaser = new AgentPayoffReleaser();
$AgentPayoffReleaser->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-企業指定放行人
/// </summary>
public class AgentPayoffReleaser {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://auth.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentPayoffReleaser simulator = new AgentPayoffReleaser();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic userData = new ExpandoObject();
userData.user_id = "phper";
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.user_data = userData;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/payoffreleaser";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-企業指定放行人
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentPayoffReleaser {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://auth.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentPayoffReleaser simulator = new AgentPayoffReleaser();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> userData = new HashMap<Object, Object>();
userData.put("user_id", "phper");
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("user_data", userData);
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/payoffreleaser");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-企業指定放行人
*/
function AgentPayoffReleaser() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://auth.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentPayoffReleaser.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
user_data: {
'user_id': "phper"
},
};
};
/**
* 取得服務位置
*/
AgentPayoffReleaser.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/payoffreleaser"
};
};
/**
* AES 256 加密
*/
AgentPayoffReleaser.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentPayoffReleaser.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentPayoffReleaser.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentPayoffReleaser.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentPayoffReleaser = new AgentPayoffReleaser();
AgentPayoffReleaser.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-企業指定放行人
"""
class AgentPayoffReleaser:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://auth.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'user_data': {
'user_id': "phper"
},
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/payoffreleaser'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentPayoffReleaser = AgentPayoffReleaser()
AgentPayoffReleaser.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"url": "https:\/\/pay.usecase.cc\/payoff\/releaser\/5dc99c4a.html"
}
撥款前須要先設定企業撥款『放行人資訊』。透過此API,可以讓企業撥款放行的人設定交易密碼,以利進行後續放行作業。
經銷商『企業指定放行人』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/payoffreleaser"} JSON格式,AES256加密資料 |
encry_data | text | 『企業指定放行人』欄位參考 JSON格式,AES256加密資料 |
『企業指定放行人』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string | 特約商店商務代號 | 必填 |
user_data | object | 放行人資訊 | 必填 『放行人資訊』欄位參考 |
success_returl | string | 設定成功導頁連結 | |
failure_returl | string | 設定失敗導頁連結 | |
homepage_url | string | 返回首頁連結 | |
return_url | string | 指定放行人設定完成後結果通知網址 |
『企業指定放行人』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『Pay Off 執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
url | string | 設定網址 | |
uid | string | UID(完成設定回報通知時驗證用) | |
key | string | 驗証碼(完成設定回報通知時驗證用) |
『企業指定放行人通知』回報欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | UID | |
key | string | 驗証碼 | |
code | string | 狀態碼 | 『處理狀態碼』值參考 |
msg | string | 狀態碼說明 | |
finished_date | string | 企業指定放行人設定完成時間(格式:yyyyMMddHHmmss) | |
store_uid | string | 特約商店商務代號 | |
user_id | string | 放行人帳號 |
建立撥款批次
<?php
/**
* 經銷商串接-建立撥款批次
*/
final class AgentPayoffRemittance
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://auth.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['tix_code'] = "405";
$rawData['estimated_date'] = "20230218";
$rawData['group_name'] = "2023/02/18第 1731 批次匯款";
$rawData['group_id'] = "202302181731";
$rawData['items'] = [
[
'id' => '00001',
'user_id' => 'payee',
'money' => 36100
],
[
'id' => '00002',
'user_id' => 'payee2',
'money' => 42600
]
];
$rawData['return_url'] = "https://api.usecase.cc/log";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/payoffremittance'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentPayoffRemittance = new AgentPayoffRemittance();
$AgentPayoffRemittance->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-建立撥款批次
/// </summary>
public class AgentPayoffRemittance {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://auth.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentPayoffRemittance simulator = new AgentPayoffRemittance();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item1 = new ExpandoObject();
item1.id = "00001";
item1.user_id = "payee";
item1.money = 36100;
items.Add(item1);
dynamic item2 = new ExpandoObject();
item2.id = "00002";
item2.user_id = "payee2";
item2.money = 42600;
items.Add(item2);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.tix_code = "405";
rawData.estimated_date = "20230218";
rawData.group_name = "2023/02/18第 1731 批次匯款";
rawData.group_id = "202302181731";
rawData.items = items;
rawData.return_url = "https://api.usecase.cc/log";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/payoffremittance";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-建立撥款批次
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentPayoffRemittance {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://auth.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentPayoffRemittance simulator = new AgentPayoffRemittance();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item1 = new HashMap<Object, Object>();
item1.put("id", "00001");
item1.put("user_id", "payee");
item1.put("money", 36100);
items.add(item1);
Map<Object, Object> item2 = new HashMap<Object, Object>();
item2.put("id", "00002");
item2.put("user_id", "payee2");
item2.put("money", 42600);
items.add(item2);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("tix_code", "405");
rawData.put("estimated_date", "20230218");
rawData.put("group_name", "2023/02/18第 1731 批次匯款");
rawData.put("group_id", "202302181731");
rawData.put("items", items);
rawData.put("return_url", "https://api.usecase.cc/log");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/payoffremittance");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-建立撥款批次
*/
function AgentPayoffRemittance() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://auth.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentPayoffRemittance.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
tix_code: "405",
estimated_date: "20230218",
group_name: "2023/02/18第 1731 批次匯款",
group_id: "202302181731",
items: [
{
'id': "00001",
'user_id': "payee",
'money': 36100
},
{
'id': "00002",
'user_id': "payee2",
'money': 42600
}
],
return_url: "https://api.usecase.cc/log",
};
};
/**
* 取得服務位置
*/
AgentPayoffRemittance.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/payoffremittance"
};
};
/**
* AES 256 加密
*/
AgentPayoffRemittance.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentPayoffRemittance.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentPayoffRemittance.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentPayoffRemittance.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentPayoffRemittance = new AgentPayoffRemittance();
AgentPayoffRemittance.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-建立撥款批次
"""
class AgentPayoffRemittance:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://auth.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'tix_code': "405",
'estimated_date': "20230218",
'group_name': "2023/02/18第 1731 批次匯款",
'group_id': "202302181731",
'items': [
{
'id': "00001",
'user_id': "payee",
'money': 36100
},
{
'id': "00002",
'user_id': "payee2",
'money': 42600
}
],
'return_url': "https://api.usecase.cc/log",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/payoffremittance'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentPayoffRemittance = AgentPayoffRemittance()
AgentPayoffRemittance.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"uid": "36",
"key": "a8f6767dcfc6861a3b6797e5505c4735",
"code": "S01",
"msg": "等待放行",
"store_uid": "289151880002",
"group_id": "202302171446",
"items": [
{
"id": "00001",
"user_id": "payee",
"money": 36100,
"finished_date": "",
"code": "C0001",
"msg": "等待放行"
},
{
"id": "00002",
"user_id": "payee2",
"money": 42600,
"finished_date": "",
"code": "C0001",
"msg": "等待放行"
}
],
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
}
撥款前,先將整批撥款資訊告知MYPAY。整批撥款資訊中,所有收款人都必須先設定好收款帳號資訊,若整批有未設定則會回應未設定資訊。
回傳欄位中有一組「uid」「key」欄位,當指定放行後撥款結果通知網址,直接收通知可以判斷此欄位是否相同以確認是我方傳遞。
若有指定放行後撥款結果通知網址,則每次放行後會回報此撥款批次最新狀態。
經銷商『建立撥款批次』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/payoffremittance"} JSON格式,AES256加密資料 |
encry_data | text | 『建立撥款批次』欄位參考 JSON格式,AES256加密資料 |
『建立撥款批次』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string | 特約商店商務代號 | 必填 |
tix_code | string | ACH代收代付交易代號(請依照實際申請填入) 測試區為405或441 參考連結(https://www.twnch.org.tw/ach/file/ACH%E4%BB%A3%E6%94%B6%E4%BB%A3%E4%BB%98%E4%BA%A4%E6%98%93%E4%BB%A3%E8%99%9F%E8%A1%A8.doc) |
必填 |
estimated_date | string | 預計撥款日期(格式為YYYYmmdd) | 必填 |
group_name | string | 批次撥款名稱 | 必填 |
group_id | string | 批次撥款編號(發動方唯一編號,限定英數字) | 必填 |
items | array | 批次撥款內容 | 必填 每筆『Pay Off 批次撥款項目』欄位參考 |
return_url | string | 放行後撥款結果通知網址 | |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『建立撥款批次』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『Pay Off 執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 批次撥款資訊回傳 | 『批次撥款回傳參數』欄位參考 |
『撥款交易細項資訊』回報欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 批次撥款UID | |
key | string | 驗証碼 | |
code | string | 批次撥款狀態碼 | 『Pay Off 撥款批次狀態碼』值參考 |
msg | string | 批次撥款狀態碼說明 | |
store_uid | string | 特約商店商務代號 | |
group_id | string | 批次撥款編號 | |
items | array | 批次撥款內容 | 每筆『Pay Off 批次撥款項目』欄位參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
批次補撥款
<?php
/**
* 經銷商串接-批次補撥款
*/
final class AgentPayoffCoveringRemittance
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://auth.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['group_id'] = "202302170941";
$rawData['items'] = [
[
'id' => '00001'
]
];
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/payoffcoveringremittance'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentPayoffCoveringRemittance = new AgentPayoffCoveringRemittance();
$AgentPayoffCoveringRemittance->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-批次補撥款
/// </summary>
public class AgentPayoffCoveringRemittance {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://auth.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentPayoffCoveringRemittance simulator = new AgentPayoffCoveringRemittance();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
ArrayList items = new ArrayList();
dynamic item = new ExpandoObject();
item.id = "00001";
items.Add(item);
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.group_id = "202302170941";
rawData.items = items;
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/payoffcoveringremittance";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-批次補撥款
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentPayoffCoveringRemittance {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://auth.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentPayoffCoveringRemittance simulator = new AgentPayoffCoveringRemittance();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
ArrayList items = new ArrayList();
Map<Object, Object> item = new HashMap<Object, Object>();
item.put("id", "00001");
items.add(item);
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("group_id", "202302170941");
rawData.put("items", items);
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/payoffcoveringremittance");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-批次補撥款
*/
function AgentPayoffCoveringRemittance() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://auth.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentPayoffCoveringRemittance.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
group_id: "202302170941",
items: [
{
'id': "00001"
}
],
};
};
/**
* 取得服務位置
*/
AgentPayoffCoveringRemittance.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/payoffcoveringremittance"
};
};
/**
* AES 256 加密
*/
AgentPayoffCoveringRemittance.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentPayoffCoveringRemittance.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentPayoffCoveringRemittance.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentPayoffCoveringRemittance.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentPayoffCoveringRemittance = new AgentPayoffCoveringRemittance();
AgentPayoffCoveringRemittance.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-批次補撥款
"""
class AgentPayoffCoveringRemittance:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://auth.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'group_id': "202302170941",
'items': [
{
'id': "00001"
}
],
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/payoffcoveringremittance'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentPayoffCoveringRemittance = AgentPayoffCoveringRemittance()
AgentPayoffCoveringRemittance.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"uid": "31",
"key": "948a80eeb7a8427076879cb3b9206990",
"code": "S01",
"msg": "等待放行",
"store_uid": "289151880002",
"group_id": "202302170941",
"items": [
{
"id": "00001",
"user_id": "payee",
"money": 36100,
"finished_date": "",
"code": "C0001",
"msg": "等待放行"
},
{
"id": "00002",
"user_id": "payee2",
"money": 42600,
"finished_date": "",
"code": "C2002",
"msg": "放行人退件"
}
],
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
}
若放行後,批次項目中有部分撥款失敗或放行人退件,則可以再發動一次補撥款。
經銷商『批次補撥款』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/payoffcoveringremittance"} JSON格式,AES256加密資料 |
encry_data | text | 『批次補撥款』欄位參考 JSON格式,AES256加密資料 |
『批次補撥款』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string | 特約商店商務代號 | 必填 |
group_id | string | 原批次撥款編號 (補撥款時,批次撥款狀態碼必須為部分撥款完成「S05」) |
必填 |
items | array | 補撥款內容 | 必填 每筆『Pay Off 補撥款項目』欄位參考 |
『批次補撥款』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『Pay Off 執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 批次撥款資訊回傳 | 『批次撥款回傳參數』欄位參考 |
放行交易
<?php
/**
* 經銷商串接-放行交易
*/
final class AgentPayoffConfirmation
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://auth.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['user_id'] = "phper";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/payoffconfirmation'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentPayoffConfirmation = new AgentPayoffConfirmation();
$AgentPayoffConfirmation->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-放行交易
/// </summary>
public class AgentPayoffConfirmation {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://auth.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentPayoffConfirmation simulator = new AgentPayoffConfirmation();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.user_id = "phper";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/payoffconfirmation";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-放行交易
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentPayoffConfirmation {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://auth.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentPayoffConfirmation simulator = new AgentPayoffConfirmation();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("user_id", "phper");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/payoffconfirmation");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-放行交易
*/
function AgentPayoffConfirmation() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://auth.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentPayoffConfirmation.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
user_id: "phper",
};
};
/**
* 取得服務位置
*/
AgentPayoffConfirmation.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/payoffconfirmation"
};
};
/**
* AES 256 加密
*/
AgentPayoffConfirmation.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentPayoffConfirmation.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentPayoffConfirmation.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentPayoffConfirmation.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentPayoffConfirmation = new AgentPayoffConfirmation();
AgentPayoffConfirmation.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-放行交易
"""
class AgentPayoffConfirmation:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://auth.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'user_id': "phper",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/payoffconfirmation'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentPayoffConfirmation = AgentPayoffConfirmation()
AgentPayoffConfirmation.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"url": "https:\/\/pay.usecase.cc\/payoff\/confirmation\/cc9d6296.html"
}
由企業指定的放行人,進行撥款放行動作。
經銷商『放行交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/payoffconfirmation"} JSON格式,AES256加密資料 |
encry_data | text | 『放行交易』欄位參考 JSON格式,AES256加密資料 |
『放行交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string | 特約商店商務代號 | 必填 |
user_id | string | 放行人帳號 | 必填 |
success_returl | string | 放行成功導頁連結 | |
failure_returl | string | 放行失敗導頁連結 | |
homepage_url | string | 返回首頁連結 |
『放行交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『票券執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
url | string | 放行網址 |
查詢交易
<?php
/**
* 經銷商串接-查詢交易
*/
final class AgentPayoffInquirer
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://auth.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['store_uid'] = $this->storeUid;
$rawData['group_id'] = "202302170941";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'api',
'cmd' => 'api/payoffinquirer'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentPayoffInquirer = new AgentPayoffInquirer();
$AgentPayoffInquirer->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-查詢交易
/// </summary>
public class AgentPayoffInquirer {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://auth.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentPayoffInquirer simulator = new AgentPayoffInquirer();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic rawData = new ExpandoObject();
rawData.store_uid = this.storeUid;
rawData.group_id = "202302170941";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "api";
rawData.cmd = "api/payoffinquirer";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-查詢交易
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentPayoffInquirer {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://auth.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentPayoffInquirer simulator = new AgentPayoffInquirer();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("store_uid", this.storeUid);
rawData.put("group_id", "202302170941");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "api");
rawData.put("cmd", "api/payoffinquirer");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-查詢交易
*/
function AgentPayoffInquirer() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://auth.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentPayoffInquirer.prototype.getRawData = function () {
return {
store_uid: this.storeUid,
group_id: "202302170941",
};
};
/**
* 取得服務位置
*/
AgentPayoffInquirer.prototype.getService = function () {
return {
service_name: "api",
cmd: "api/payoffinquirer"
};
};
/**
* AES 256 加密
*/
AgentPayoffInquirer.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentPayoffInquirer.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentPayoffInquirer.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentPayoffInquirer.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentPayoffInquirer = new AgentPayoffInquirer();
AgentPayoffInquirer.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-查詢交易
"""
class AgentPayoffInquirer:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://auth.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'store_uid': self.storeUid,
'group_id': "202302170941",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'api',
'cmd': 'api/payoffinquirer'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentPayoffInquirer = AgentPayoffInquirer()
AgentPayoffInquirer.run()
回傳 JSON 結構如下:
{
"code": "B200",
"msg": "執行成功",
"content": {
"uid": "31",
"key": "948a80eeb7a8427076879cb3b9206990",
"code": "S01",
"msg": "等待放行",
"store_uid": "289151880002",
"group_id": "202302170941",
"items": [
{
"id": "00001",
"user_id": "payee",
"money": 36100,
"finished_date": "",
"code": "C0001",
"msg": "等待放行"
},
{
"id": "00002",
"user_id": "payee2",
"money": 42600,
"finished_date": "",
"code": "C2002",
"msg": "放行人退件"
}
],
"echo_0": "",
"echo_1": "",
"echo_2": "",
"echo_3": "",
"echo_4": ""
}
}
可透過此API查詢指定批次撥款的最新撥款狀態。
經銷商『查詢交易』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "api", "cmd": "api\/payoffinquirer"} JSON格式,AES256加密資料 |
encry_data | text | 『查詢交易』欄位參考 JSON格式,AES256加密資料 |
『查詢交易』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
store_uid | string | 特約商店商務代號 | 必填 |
group_id | string | 批次撥款編號 | 必填 |
『查詢交易』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 執行狀態碼 | 『Pay Off 執行狀態碼』值參考 |
msg | string | 執行狀態訊息 | |
content | object | 查詢交易細項資訊 | 『撥款交易細項資訊』欄位參考 |
忘記交易密碼
<?php
/**
* 經銷商串接-忘記交易密碼
*/
final class AgentForgotTp
{
/**
* 經銷商商務代號
* @var string
*/
public $agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
* @var string
*/
public $agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號(代特約商店發動)
* @var string
*/
public $storeUid = "289151880002";
/**
* 串接交易位置
* @var string
*/
public $url = "https://pay.usecase.cc/api/agent";
/**
* 取得串接欄位資料
* @return array
*/
public function getRawData()
{
$rawData = array();
$rawData['user_id'] = "phper";
$rawData['homepage_url'] = "http://www.mypay.com.tw";
return $rawData;
}
/**
* 取得服務位置
* @return array
*/
public function getService()
{
return array(
'service_name' => 'ocp',
'cmd' => 'api/forgottp'
);
}
/**
* AES 256 加密
* @param array $fields
* @param string $key
* @return string
*/
public function encrypt($fields, $key)
{
$data = json_encode($fields);
$size = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($size);
$data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($iv . $data);
return $data;
}
/**
* 資料 POST 到主機
* @param array $postData
* @return mixed
*/
public function post($postData = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* 取得送出欄位資料
* @return array
*/
public function getPostData ()
{
$postData = array();
$postData['agent_uid'] = $this->agentUid;
$postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
$postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
return $postData;
}
/**
* 執行
*/
public function run()
{
$json = $this->post($this->getPostData());
echo $json;
}
}
$AgentForgotTp = new AgentForgotTp();
$AgentForgotTp->run();
?>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
/// <summary>
/// 經銷商串接-忘記交易密碼
/// </summary>
public class AgentForgotTp {
/// <summary>
/// 經銷商商務代號
/// </summary>
public string agentUid = "518169081001";
/// <summary>
/// 經銷商金鑰或認證碼
/// </summary>
public string agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/// <summary>
/// 特約商店商務代號
/// </summary>
public string storeUid = "289151880002";
/// <summary>
/// 串接交易位置
/// </summary>
public string url = "https://pay.usecase.cc/api/agent";
/// <summary>
/// 執行
/// </summary>
static void Main() {
AgentForgotTp simulator = new AgentForgotTp();
//僅限走https的Tls 1.2以上版本
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//發送至遠端
var result = simulator.Post(simulator.GetPostData());
System.Console.WriteLine(result);
}
/// <summary>
/// 取得串接欄位資料
/// </summary>
private dynamic GetRawData() {
dynamic rawData = new ExpandoObject();
rawData.user_id = "phper";
rawData.homepage_url = "http://www.mypay.com.tw";
return rawData;
}
/// <summary>
/// 取得服務位置
/// </summary>
private ServiceRequest GetService() {
ServiceRequest rawData = new ServiceRequest();
rawData.service_name = "ocp";
rawData.cmd = "api/forgottp";
return rawData;
}
/// <summary>
/// 取得送出欄位資料
/// </summary>
private NameValueCollection GetPostData() {
string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整
//產生AES向量
var IV = GetBytesIV();
//進行加密
var data_encode = Encrypt(data_json, this.agentKey, IV);
var svr_encode = Encrypt(svr_json, this.agentKey, IV);
//請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
//若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);
NameValueCollection postData = new NameValueCollection();
postData["agent_uid"] = this.agentUid;
postData["service"] = svr_toUrlEncode;
postData["encry_data"] = data_toUrlEncode;
return postData;
}
/// <summary>
/// AES 256 加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="byteIV"></param>
/// <returns></returns>
private string Encrypt(string data, string key, byte[] byteIV) {
var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
var enBytes = AES_Encrypt(data, byteKey, byteIV);
return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
}
/// <summary>
/// AES 256 加密處理
/// </summary>
/// <param name="original"></param>
/// <param name="key"></param>
/// <param name="iv"></param>
/// <returns></returns>
private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
try {
var data = Encoding.UTF8.GetBytes(original);
var cipher = Aes.Create().CreateEncryptor(key, iv);
var de = cipher.TransformFinalBlock(data, 0, data.Length);
return de;
} catch {
return null;
}
}
/// <summary>
/// 轉換Bytes
/// </summary>
/// <param name="a"></param>
/// <param name="arryB"></param>
/// <returns></returns>
private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
List < byte > c = new List < byte > ();
c.AddRange(a);
arryB.ToList().ForEach(b => {
c.AddRange(b);
});
return c.ToArray();
}
/// <summary>
/// 產生AES的IV
/// </summary>
/// <returns></returns>
private static byte[] GetBytesIV() {
var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
aes.KeySize = 256;
aes.GenerateIV();
return aes.IV;
}
/// <summary>
/// 資料 POST 到主機
/// </summary>
/// <param name="pars"></param>
/// <returns></returns>
private string Post(NameValueCollection pars) {
string result = string.Empty;
string param = string.Empty;
if (pars.Count > 0) {
pars.AllKeys.ToList().ForEach(key => {
param += key + "=" + pars[key] + "&";
});
if (param[param.Length - 1] == '&') {
param = param.Remove(param.Length - 1);
}
}
byte[] bs = Encoding.UTF8.GetBytes(param);
try {
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using(Stream reqStream = req.GetRequestStream()) {
reqStream.Write(bs, 0, bs.Length);
}
using(WebResponse wr = req.GetResponse()) {
Encoding myEncoding = Encoding.GetEncoding("UTF-8");
using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
result = myStreamReader.ReadToEnd();
}
}
req = null;
} catch (WebException ex) {
throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
}
return result;
}
}
/// <summary>
/// 串接服務請求欄位
/// </summary>
public class ServiceRequest {
public string service_name { get; set; }
public string cmd { get; set; }
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
* 經銷商串接-忘記交易密碼
* 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
* 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
* 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
* 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
*/
public class AgentForgotTp {
/**
* 經銷商商務代號
*/
String agentUid = "518169081001";
/**
* 經銷商金鑰或認證碼
*/
String agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
/**
* 特約商店商務代號
*/
String storeUid = "289151880002";
/**
* 串接交易位置
*/
String url = "https://pay.usecase.cc/api/agent";
/**
* 執行
* @param args
*/
public static void main(String[] args) {
AgentForgotTp simulator = new AgentForgotTp();
String json = simulator.post(simulator.getPostData());
System.out.print(json);
}
@SuppressWarnings(value = { "unchecked", "deprecation" })
/**
* 取得串接欄位資料
* @return 串接原始資料
*/
public Map getRawData() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("user_id", "phper");
rawData.put("homepage_url", "http://www.mypay.com.tw");
return rawData;
}
/**
* 取得服務位置
* @return 串接服務資料
*/
public Map getService() {
Map<Object, Object> rawData = new HashMap<Object, Object>();
rawData.put("service_name", "ocp");
rawData.put("cmd", "api/forgottp");
return rawData;
}
/**
* AES 256 加密
* @param rawData 原始資料
* @param AesKey AES256金鑰字串
* @return 轉換成Base64資料
*/
public String encrypt(Map rawData, String AesKey) {
try {
ObjectMapper objMapper = new ObjectMapper();
byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
byte[] key = AesKey.getBytes(UTF_8);
// 16 bytes is the IV size for AES256
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()));
// Random iv
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[16];
rng.nextBytes(ivBytes);
cipher.init(true, new ParametersWithIV(new KeyParameter(key),
ivBytes));
byte[] outBuf = new byte[cipher.getOutputSize(data.length)];
int processed = cipher
.processBytes(data, 0, data.length, outBuf, 0);
processed += cipher.doFinal(outBuf, processed);
byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
System.arraycopy(outBuf, 0, outBuf2, 16, processed);
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(outBuf2);
return base64;
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
/**
* 資料 POST 到主機
* @param qstr 串接資料
* @return 服務回傳JSON資訊
*/
public String post(String qstr) {
String result = "";
try {
// 資料
byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);
URL iurl = new URL(this.url);
SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
con.setSSLSocketFactory(sc.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length",
String.valueOf(qstr_bytes.length));
con.setRequestProperty("Accept-Charset", "UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.getOutputStream()
.write(qstr.getBytes(Charset.forName("UTF-8")));
con.getOutputStream().flush();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream(), "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\r\n");
}
try {
result = response.toString();
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return result;
}
/**
* 取得送出欄位資料
* @return POST完整資料
*/
public String getPostData() {
String postData = "";
try {
// Base64需要使用UrlEncode做傳輸
String data_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
String svr_toUrlEncode = URLEncoder.encode(
this.encrypt(this.getService(), this.agentKey), "UTF-8");
postData = "agent_uid=" + this.agentUid + "&service="
+ svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return postData;
}
}
const crypto = require('crypto');
const httpRequest = require('https');
/**
* 經銷商串接-忘記交易密碼
*/
function AgentForgotTp() {
// 經銷商商務代號
this.agentUid = "518169081001";
// 經銷商金鑰或認證碼
this.agentKey = "0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
// 特約商店商務代號
this.storeUid = "289151880002";
// 串接交易位置
this.url = "https://pay.usecase.cc/api/agent";
};
/**
* 取得串接欄位資料
*/
AgentForgotTp.prototype.getRawData = function () {
return {
user_id: "phper",
homepage_url: "http://www.mypay.com.tw",
};
};
/**
* 取得服務位置
*/
AgentForgotTp.prototype.getService = function () {
return {
service_name: "ocp",
cmd: "api/forgottp"
};
};
/**
* AES 256 加密
*/
AgentForgotTp.prototype.encrypt = function (fields, key) {
let eData = JSON.stringify(fields);
const blockSize = 16;
const iv = crypto.randomBytes(blockSize);
const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
let tmpCipher = encryptor.update(Buffer.from(eData));
let finalCipher = encryptor.final();
const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
return data;
};
/**
* 資料 POST 到主機
*/
AgentForgotTp.prototype.post = function (postData) {
return new Promise((res, rej) => {
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
rejectUnauthorized: false
};
let send_process = httpRequest.request(this.url, options, (api_res) => {
let res_data = "";
api_res.on('data', (tmp_data) => {
res_data += tmp_data;
});
api_res.on('end', () => {
res(res_data);
});
});
send_process.write(JSON.stringify(postData));
send_process.end();
});
};
/**
* 取得送出欄位資料
*/
AgentForgotTp.prototype.getPostData = function () {
return {
"agent_uid": this.agentUid,
"service": this.encrypt(this.getService(), this.agentKey),
"encry_data": this.encrypt(this.getRawData(), this.agentKey)
};
};
/**
* 執行
*/
AgentForgotTp.prototype.run = async function () {
json = await this.post(this.getPostData())
console.log(json);
};
AgentForgotTp = new AgentForgotTp();
AgentForgotTp.run();
# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes
"""經銷商串接-忘記交易密碼
"""
class AgentForgotTp:
# 經銷商商務代號
agentUid = "518169081001";
# 經銷商金鑰或認證碼
agentKey = b"0DZP5XgV1dLXXNQqNUFZ7UXvSP6DBalS";
# 特約商店商務代號
storeUid = "289151880002"
# 串接交易位置
url = "https://pay.usecase.cc/api/agent"
def getRawData(self):
"""取得串接欄位資料
Returns:
{dict}: 欄位資料
"""
rawData = {
'user_id': "phper",
'homepage_url': "http://www.mypay.com.tw",
}
return rawData
def getService(self):
"""取得服務位置
Returns:
{dict}: 服務位置資料
"""
return {
'service_name': 'ocp',
'cmd': 'api/forgottp'
}
def encrypt(self, fields, key):
"""AES 256 加密
Args:
fields {dict}: 欄位資料
key {bytes}: AES金鑰
Returns:
{string}: 加密資料
"""
data = json.dumps(fields, separators=(',', ':'))
data = Padding.pad(data.encode('utf-8'), AES.block_size)
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.encrypt(data)
data = base64.b64encode(iv + data)
return data
def post(self, postData):
"""資料 POST 到主機
Args:
postData {dict}: 欄位資料
Returns:
{string}: JSON資料
"""
result = requests.post(self.url, postData)
return result.text
def getPostData(self):
"""取得送出欄位資料
Returns:
{dict}: 欄位資料
"""
postData = {
'agent_uid': self.agentUid,
'service': self.encrypt(self.getService(), self.agentKey),
'encry_data': self.encrypt(self.getRawData(), self.agentKey)
}
return postData
def run(self):
"""執行
"""
json = self.post(self.getPostData())
print(json)
AgentForgotTp = AgentForgotTp()
AgentForgotTp.run()
回傳 JSON 結構如下:
{
"url": "https:\/\/ocpwallet.usecase.cc\/open\/28cac16858a344b99d2bfe3402882c66",
"code": "B200",
"msg": "執行成功"
}
企業指定的撥款放行人若要變更放行時輸入的交易密碼,可以透過此API變更。
經銷商『忘記交易密碼』參數說明
欄位 | 型態 | 說明 |
---|---|---|
agent_uid | string(16) | 經銷商商務代號 |
service | text | {"service_name": "ocp", "cmd": "api\/forgottp"} JSON格式,AES256加密資料 |
encry_data | text | 『忘記交易密碼』欄位參考 JSON格式,AES256加密資料 |
『忘記交易密碼』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
user_id | string | 經銷商/特店會員編號 | 必填 |
homepage_url | string | 返回首頁連結 | 必填 |
『忘記交易密碼』回傳欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
code | string | 回傳碼 | 『忘記交易密碼執行狀態碼』值參考 |
msg | string | 回傳訊息 | |
url | string | 導頁網址 |
其他關聯欄位說明
關聯欄位
『收款人資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
user_id | string | 收款人帳號 | 必填 |
user_real_name | string | 收款人真實姓名 | |
user_sn_type | int | 1:身分證,2:統一證號,3:護照號碼 付款人為本國人為1,外國人2 or 3 | 『證號類型』值參考 |
user_sn | string | 收款人身分證/統一證號/護照號碼 | |
user_cellphone_code | string | 收款人行動電話國碼 | |
user_cellphone | string | 收款人行動電話 | |
user_email | string | 收款人 E-Mail | |
bank_code | string | 收款人銀行帳戶:銀行代碼 | |
bank_branch_code | string | 收款人銀行帳戶: 分行代碼 | |
bank_account_number | string | 收款人銀行帳戶:銀行帳號 |
『放行人資訊』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
user_id | string | 放行人帳號 | 必填 |
user_real_name | string | 放行人真實姓名 | |
user_sn_type | int | 1:身分證,2:統一證號,3:護照號碼 付款人為本國人為1,外國人2 or 3 | 『證號類型』值參考 |
user_sn | string | 放行人身分證/統一證號/護照號碼 | |
user_cellphone_code | string | 放行人行動電話國碼 | |
user_cellphone | string | 放行人行動電話 | |
user_email | string | 放行人 E-Mail |
『Pay Off 批次撥款項目』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
id | string | 撥款代碼-本批次撥款項目編號(本批次唯一,限定英數字) | 必填 |
user_id | string | 收款人帳號 | 必填 |
money | float | 撥款金額(必須為整數) | 必填 |
『批次撥款回傳參數』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
uid | string | 批次撥款UID | |
key | string | 驗証碼 | |
code | string | 批次撥款狀態碼 | 『Pay Off 撥款批次狀態碼』值參考 |
msg | string | 批次撥款狀態碼說明 | |
store_uid | string | 特約商店商務代號 | |
group_id | string | 批次撥款編號 | |
items | array | 批次撥款內容 | 每筆『Pay Off 批次撥款項目』欄位參考 |
echo_0 | string | 自訂回傳參數 1 | |
echo_1 | string | 自訂回傳參數 2 | |
echo_2 | string | 自訂回傳參數 3 | |
echo_3 | string | 自訂回傳參數 4 | |
echo_4 | string | 自訂回傳參數 5 |
『Pay Off 批次撥款項目』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
id | string | 撥款代碼-本批次撥款項目編號(本批次唯一) | |
user_id | string | 收款人帳號 | |
money | int | 撥款金額 | |
finished_date | string | 撥款成功完成時間(格式YYYYmmddHHiiss) | |
code | string | 撥款狀態碼 | 『Pay Off 撥款狀態碼』值參考 |
msg | string | 撥款狀態說明 |
『Pay Off 補撥款項目』欄位
參數名稱 | 型態 | 說明 | 必須 |
---|---|---|---|
id | string | 撥款代碼-本批次補撥款項目編號 (可補撥項目,目前項目狀態碼應為撥款失敗C2001或放行人退件C2002) |
值的定義
『Pay Off 執行狀態碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
100 | string | 資料不正確 | |
400 | string | 系統錯誤 | |
B200 | string | 執行成功 | |
B500 | string | 執行失敗 |
『Pay Off 撥款批次狀態碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
S01 | string | 等待放行 | |
S03 | string | 執行批次撥款中 | |
S04 | string | 全部撥款完成 | |
S05 | string | 部分撥款完成 |
『Pay Off 撥款狀態碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
C0001 | string | 等待放行 | |
C1001 | string | 撥款成功 | |
C2001 | string | 撥款失敗 | |
C2002 | string | 放行人退件 |
『證號類型』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
1 | integer | 身份證字號(預設) | |
2 | integer | 統一證號 | |
3 | integer | 護照號碼 |
『忘記交易密碼執行狀態碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
100 | string | 資料不正確 | |
400 | string | 系統錯誤 | |
B200 | string | 執行成功 | |
B500 | string | 執行失敗 | |
B600 | string | 此會員沒設過交易密碼,不需執行忘記交易密碼流程 |
『處理狀態碼』值內容
值 | 型態 | 說明 | 備註 |
---|---|---|---|
200 | string | 資料正確 | |
A0002 | string | 未完成設定 | |
250 | string | 設定成功 | |
300 | string | 設定失敗 |
附錄一:銀行帳戶
測試區收款帳戶設定
銀行代碼426
1100000000003326 AF 該戶為警示戶
1100000000003001 A0-交易成功 (一般活儲正常戶)
0099000000003001 A0-交易成功 (一般活儲正常戶)
0011000000003001 A0-交易成功 (一般活儲正常戶)
1100000000003304 A2 無此帳戶
1100000000003322 A7 帳戶已結清
正式區可接受匯款銀行
附錄二:金鑰管理
- 交易金鑰重新發送與變更
附錄三:資料加密方式說明
- 所有的API送出HTTPs請求之欄位中,service 和 encry_data 欄位皆進行 AES256+BASE64 加密處理。
- AES加密,格式為CBC,長度為256bits,金鑰長度32,IV長度16,傳遞內文為加密後組合IV並經過Base64轉換後傳出。
- IV資料建議隨機產生。
PHP加密示意:
AesEncrypt -> base64_ecode($IV . $JSON)
C#加密示意:
AesEncrypt -> (bytes)IV+(bytes)Json -> toBase64
Java加密示意:
AesEncrypt -> (bytes)IV+(bytes)Json -> toBase64
Node.js加密示意:
AesEncrypt -> concat([IV,JSON], [IV_SIZE,JSON_SIZE]) -> toString('base64')
Python加密示意:
AesEncrypt -> (bytes)IV+(bytes)Json -> base64.b64encode
附錄四:API模擬串接服務
提供模擬使用HTTP Protocol,透過POST方式傳遞資料到MYTIX, 並且得到回傳結果。