[day4] 安全签章 - 产生订单 & 签章(Sign)

准备讯息文本

依照参数说明,建立订单的资料结构(DAY3-参考),详细参数规格可以在永丰API技术规格文件内找到,此处先以订单建立(OrderCreate)API进行测试,订单细节如下:

故使用的参数为:

以Python实作:

neworder = APIModel.ReqOrderCreate(ShopNo="NA0249_001", OrderNo="2021091500001", Amount=40400, \
            PrdtName="IPhone 13 Pro Max 256g", ReturnURL="https://0.0.0.0/store/Return", \
                BackendURL="https://0.0.0.0/bakcend", PayType="C", AutoBilling="Y", PayTypeSub="ONE")

这边吐槽一下信用卡API测试环境只能测试一次付清,否则会跳E0602 - 收款方式未启用错误,另外还有预计自动请款天数,在设定自动请款时按照说明书应该会忽略,结果会跳日期范围不正确错误,请款日期范围也不是文件上的1-21天,而是1-7天

计算签章Sign

在取得Nonce、HashID、讯息文本等三个参数後,才能够进行安全签章(Sign)计算,计算方式概述:

  1. 移除讯息文本中空的参数与节点参数(如留空的参数与ATMParam与CardParam)
  2. 将参数以不分大小写方式递增排序
  3. 以[参数名称1]=[数值1]&[参数名称2]=[数值2].....的方式串接参数组成字串
  4. 加上Nonce与HashID
  5. 进行字串SHA256计算

以上节iPhone的信用卡订单为范例,产生的讯息文本为:

{
    "ShopNo": "NA0249_001",
    "OrderNo": "2021091500002",
    "Amount": 40400,
    "CurrencyID": "TWD",
    "PrdtName": "IPhone 13 Pro Max 256g",
    "Memo": "",
    "Param1": "",
    "Param2": "",
    "Param3": "",
    "ReturnURL": "https://0.0.0.0/store/Return",
    "BackendURL": "https://0.0.0.0/bakcend",
    "PayType": "C",
    "ATMParam": {
        "ExpireDate": ""
    },
    "CardParam": {
        "AutoBilling": "Y",
        "ExpBillingDays": 7,
        "ExpMinutes": 10,
        "PayTypeSub": "ONE"
    }
}

进行步骤1.移除讯息文本中空的参数与节点参数(如留空的参数与ATMParam与CardParam):

{
    "ShopNo": "NA0249_001",
    "OrderNo": "2021091500002",
    "Amount": 40400,
    "CurrencyID": "TWD",
    "PrdtName": "IPhone 13 Pro Max 256g",
    "ReturnURL": "https://0.0.0.0/store/Return",
    "BackendURL": "https://0.0.0.0/bakcend",
    "PayType": "C",
}

进行步骤2.将参数以不分大小写方式递增排序、3. 以[参数名称1]=[数值1]&[参数名称2]=[数值2].....的方式串接参数组成字串,记得去掉末尾的'&'

order = "Amount=40400&BackendURL=https://0.0.0.0/bakcend&CurrencyID=TWD&OrderNo=2021091500002&PayType=C&PrdtName=IPhone 13 Pro Max 256g&ReturnURL=https://0.0.0.0/store/Return&ShopNo=NA0249_001"

进行步骤4. 加上Nonce与HashID

nonce = "NjM3NjczMjQwNzM1NTAuOTo5ZWE1MmFhYzk0NDgwMzljY2RiNjhjOGU0MGU3ODc0NzFiMTIwNmNkMTViZWU4MzUwZDU3Zjg1M2VhNjIwODRj"
HashID = "17D8E6558DC60E702A6B57E1B9B7060D"

str_before_sign = "Amount=40400&BackendURL=https://0.0.0.0/bakcend&CurrencyID=TWD&OrderNo=2021091500002&PayType=C&PrdtName=IPhone 13 Pro Max 256g&ReturnURL=https://0.0.0.0/store/Return&ShopNo=NA0249_001NjM3NjczMjQwNzM1NTAuOTo5ZWE1MmFhYzk0NDgwMzljY2RiNjhjOGU0MGU3ODc0NzFiMTIwNmNkMTViZWU4MzUwZDU3Zjg1M2VhNjIwODRj17D8E6558DC60E702A6B57E1B9B7060D"

进行步骤5. 进行字串SHA256计算

sign = "3c883d53f7732ec7c3f8c9d0232691545855b60507b199094a4cde71c911f522"

以下为Python完整实作:

'''
Sample Env.ini
[App]
Version = 1.0.0
ShopNo = BA0026_001
A1 = 86D50DEF3EB7400E
A2 = 01FD27C09E5549E5
B1 = 9E004965F4244953
B2 = 7FB3385F414E4F91

[Server]
Api_URL = https://apisbx.sinopac.com/funBIZ/QPay.WebAPI/api/Order
Nonce_URL = https://apisbx.sinopac.com/funBIZ/QPay.WebAPI/api/Nonce
'''
def main():
  env = ConfigParser()
  env.read('env.ini')
  Hash = SimpleNamespace(A1 = env['App']['A1'], A2 = env['App']['A2'], B1 = env['App']['B1'], B2 = env['App']['B2'])
  cfg = SimpleNamespace(Version = env['App']['Version'], ShopNo = env['App']['ShopNo'], HashID = HashID(Hash))
  neworder = APIModel.ReqOrderCreate(ShopNo="NA0249_001", OrderNo="2021091500002", Amount=40400, PrdtName="IPhone 13 Pro Max 256g", ReturnURL="https://0.0.0.0/store/Return",                       BackendURL="https://0.0.0.0/bakcend", PayType="C", AutoBilling="Y", PayTypeSub="ONE")
  OrderCreate(neworder, cfg)

def OrderCreate(origin, cfg):
  nonce = GetNonce(cfg)
  sign = GenSign(origin, nonce, cfg.HashID)

def GetNonce(cfg):
  payload = json.dumps({"ShopNo":cfg.ShopNo}, indent=4)
  resp = APIPm.sendreq(url=APIPm.nonceservice, data=payload)
  return json.loads(resp.text)['Nonce']

def GenSign(origin, Nonce:str, HashID:str):
  SignStr = ""
  #不分大小写排序变数
  for parm in sorted(origin.__dict__, key=lambda v: v.upper()):
      val = origin.__dict__[parm]
      # print(f"Parm:{parm}, Val:{val}, Types:{type(val)}")
      if(not type(val) == SimpleNamespace and origin.__dict__[parm] != None):
          if(type(val) == str and not val):continue
          SignStr = SignStr + f"{parm}={origin.__dict__[parm]}&"
  SignStr = SignStr.removesuffix('&') + Nonce + HashID
  sign = hashlib.sha256(SignStr.encode('utf-8')).hexdigest().upper()
  return sign

如何产生签章大家都会了吗;阿好像忘了写怎麽在Python内丢Request,明天补写,斯米麻赛


<<:  [Day 7] 网页的开头 App Bar

>>:  Day-15 消逝於旧时代的 SEGA 最终梦想、复活於新电视的 DreamCast

DAY15:玉山人工智慧挑战赛-中文手写字辨识(Pytorch 自订义资料集)

资料扩增 我们组的资料扩增这部分,因为第一次比赛,这个方法效果没有到非常好,采取的是用mask的方式...

Day13 javascript 类型转换

JavaScript 变数可以转换为新变数或其他资料类型,就目前我所知道的大概可以分成两种: 1.通...

SQL资料库备份与还原

接着实作SQL的备份还原, 看他与NoSQL有何不同. 由於在新建资料库的时候都采用预设值, 因此自...

Day11:开发 MVP

开发 mvp ...

【图解演算法教学】二元树 Traversal

Youtube教学影片连结:https://bit.ly/2ECHcoQ 这次带大家深度了解二元树...