在昨天我们度过最大难关加密了,之後应该会轻松许多吧?
API 呼叫流程如下
步骤 1, 2, 3 目前都是我们已经会的!
第 4 步骤的 API Request 需求如下
快速说明这六个参数
Version
: 固定值 1.0.0
ShopNo
: 固定值 根据永丰给你的编号输入APIService
: 有三种变化,OrderCreate
(建立订单)、OrderQuery
(订单详情)、OrderPayQuery
(订单付款资讯)Nonce
: 利用 ShopNo
对 API 请求一个随机值Sign
: 订单内容的签章,避免传送过程被窜改Message
: 加密过後的订单内容我们今天会聚集在 API Service 的 OrderCreate 上面
我以信用卡为例,订单内容如下
{
"ShopNo": shop_no, ## 商家编号
"OrderNo": "A202109150001", ## 订单编号 (商家自行产生)
"Amount": 50000, ## 金额,最後两位为小数 (输入50000,实际上付款为 500.00)
"CurrencyID": "TWD", ## 币别,目前只有台币这个选项
"PayType": "A", ## A 代表 ATM 转帐
"CardParam": { ## 信用卡的参数
"AutoBilling": "Y", ## 自动请款
"ExpBillingDays": "", ## 自动请款天数
"ExpMinutes": "", ## 付款连结有效时间
"PayTypeSub": "" ## 付款子项目 (一次付清)
},
"PrdtName": "OrderCreate_CreditCard_Example", ## 产品名称
"ReturnURL": "<URL>", ## 付款成功时 redirect 的网页
"BackendURL": "<URL>" ## 订单完成付款时,会通知到这里
}
只要把上面的资讯加密後输入到下面 Message 栏位,就可以发出 Query 了!
{
'Version': '1.0.0',
'ShopNo': shop_no,
'APIService': 'OrderCreate',
'Sign': sign,
'Nonce': nonce,
'Message': msg
}
API 回传的内容也跟 上面一样,差别为内容是永丰要跟你说的讯息
程序码非常简单,东西填一填就可以发出 Request 了
def apiService(service, sign, nonce, msg):
api_data = {
'Version': '1.0.0',
'ShopNo': shop_no,
'APIService': service,
'Sign': sign,
'Nonce': nonce,
'Message': msg
}
r = requests.post(order_url, json = api_data)
resp = json.loads(r.content)
return (resp['Sign'], resp['Nonce'], resp['Message'])
resp_sign, resp_nonce, resp_message = apiService('OrderCreate', signature, nonce, enc_message)
那我们今天就说到这里,明天会说明其他两个 API Service!
一样在最後附上程序码~
from __future__ import unicode_literals
import requests
import hashlib
import codecs
import json
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
shop_no = '<shop_no>'
sinopac_hash = {
'a1': '',
'a2': '',
'b1': '',
'b2': ''
}
nonce_url = 'https://apisbx.sinopac.com/funBIZ/QPay.WebAPI/api/Nonce'
order_url = 'https://apisbx.sinopac.com/funBIZ/QPay.WebAPI/api/Order'
def getNonce():
nonce_data = {
'ShopNo': shop_no
}
r = requests.post(nonce_url, json=nonce_data)
return json.loads(r.content)['Nonce']
def calcHashID():
a1 = sinopac_hash['a1']
a2 = sinopac_hash['a2']
b1 = sinopac_hash['b1']
b2 = sinopac_hash['b2']
xor1 = hex(int(a1, base=16)^int(a2, base=16))
xor2 = hex(int(b1, base=16)^int(b2, base=16))
hash_id = xor1[2:]+xor2[2:]
return hash_id.upper()
def calcIV(nonce):
s = hashlib.sha256()
s.update(nonce.encode('utf-8'))
h = s.hexdigest()
return h[-16:].upper()
def calcSign(msg_content, nonce, hash_id):
sign_msg = msg_content+nonce+hash_id
s = hashlib.sha256()
s.update(sign_msg.encode('utf-8'))
h = s.hexdigest()
return h.upper()
def parseQueryData(msg_param):
if type(msg_param) != dict:
return
order_message = dict(sorted(msg_param.items(), key = lambda x: x[0]))
message = ''
for k, v in order_message.items():
if type(v) == dict or v == '':
continue
message += f"{k}={v}&"
return message[:-1]
def CBCEncrypt(key, iv, data):
cipher = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
return (cipher.encrypt(pad(data.encode('utf-8'), AES.block_size)))
def CBCDecrypt(key, iv, data):
data = codecs.decode(data, "hex")
cipher = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
return unpad(cipher.decrypt(data), AES.block_size)
def apiService(service, sign, nonce, msg):
api_data = {
'Version': '1.0.0',
'ShopNo': shop_no,
'APIService': service,
'Sign': sign,
'Nonce': nonce,
'Message': msg
}
r = requests.post(order_url, json = api_data)
resp = json.loads(r.content)
return (resp['Sign'], resp['Nonce'], resp['Message'])
def orderCreate(order_create):
nonce = getNonce()
hash_id = calcHashID()
iv = calcIV(nonce)
content = parseQueryData(order_create)
signature = calcSign(content, nonce, hash_id)
msg = json.dumps(order_create, ensure_ascii=False).replace(' ','')
enc_message = CBCEncrypt(hash_id, iv, msg).hex().upper()
resp_sign, resp_nonce, resp_message = apiService('OrderCreate', signature, nonce, enc_message)
resp_iv = calcIV(resp_nonce)
temp = CBCDecrypt(hash_id, resp_iv, resp_message)
print(json.loads(temp))
order_create = {
"ShopNo": shop_no,
"OrderNo": "A202109150006",
"Amount": 51000,
"CurrencyID": "TWD",
"PayType": "C",
"CardParam": {
"AutoBilling": "Y"
},
"PrdtName": "OrderCreate_CreditCard_Example",
"ReturnURL": "http://10.11.22.113:8803/QPay.ApiClient/Store/Return",
"BackendURL": "http://10.11.22.113:8803/QPay.ApiClient/AutoPush/PushSuccess"
}
orderCreate(order_create)
质询握手身份验证协议(Challenge-Handshake Authentication Prot...
Hi Dai Gei Ho~ 我是 Winnie ~ 今天的文章中,我们要来说说 v-if & v-...
在我们定义变量的时候都要加上像是 var、const、let等关键字, 那麽他们在作用域中又代表了甚...
前言 本篇会示范如何在 Ruby on Rails 中产 QR Code,可透过 rqrcode 或...
常常有时候在阅读较大的专案时 没有定位档案位置的功能的话很难找到该 Class 的位置 大家可以找到...