Day09 - [丰收款] 安全无虞後,开始建立订单:ATM虚拟帐号篇 (1)

先前花了几天的时间,终於把每次API发送前的安全规定的细碎精工给搞定了,也开了篇幅写了一些关於十六进位转换与Base64的差异等的小专题後,接下来就可以再回到使用情境面,来看我们身为商家角色要为我们的电商平台顾客提供怎麽样的服务。

当我们顾客在选购商品服务到购物车後,确认为无时订单会在此时建立,接着就要进到电商交易买卖的重头戏--线上付款

建立订单且选择提供顾客的付款方式

永丰银行APIs的服务就可以在这个阶段提供金流服务给客户,目前提供了两个线上付款的服务:

  • 提供虚拟帐号供顾客进行转帐付款服务
  • 提供信用卡线上刷卡服务 (又分为有无信用卡3D验证)

以上无论哪一种,在永丰API对应到的服务名称都是OrderCreate

实际呼叫OrderCreate:虚拟帐号篇

提供转帐用的虚拟帐号给顾客,与信用卡刷卡、行动支付等比较起来,会是一个较不即时的行为。多半会给予顾客一定的期限,在顾客於一定时间内完成转帐付款之後,我们预期会由永丰API主动告知我们(电商平台)顾客已完成付款,并且我们会把相关的订单付款状态作更新。

https://ithelp.ithome.com.tw/upload/images/20210923/20130354NXTytMzxDK.png

阶段一:由我们呼叫永丰API

  1. 订单成立且顾客选择希望付款方式为「银行转帐」
  2. 我们依付款方式,呼叫OrderCreate API,并告知使用「虚拟帐号」服务。
    • 在这个步骤我们会顺便传送一个叫BackendURL的值,是为後续通知我们顾客付款状态的更新
  3. 取得API的回应,其中包含由永丰银行依订单产生的状态、相关虚拟帐号等资讯,不过在此永丰会将回传结果进行加密,我们需要反过来使用AES方式解密才能取得其中的交易资讯JSON。
  4. 显示在我们的页面上,提示顾客转帐的虚拟帐号,或转至永丰提供的WebATM服务

阶段二:消费者付款行为
5. 消费者可依期限内,透过其惯用的方法进行转帐付款 (可以是实体ATM、线上非约定转帐、线上WebATM…)

阶段三:永丰API端主动通知我们
6. 在永丰银行那端,只要在他所发出的虚拟帐号被缴款後,会有一个Mapping机制对应到当初我们传送的BackendURL,因此会将该笔订单的付款状态查询代码(PayToken)传到我们准备的接收网址。

阶段四:确认付款状态
7. 我们提供的网址若被永丰呼叫时,若能顺利取得传过来的PayToken,当然要自行撰写程序去作好PayToken的储存与管理工作。
8. 只要上面这个步骤有确实收到PayToken,就要先在Response中回报「成功结案」给永丰API。 (不然永丰API会再继续发PayToken)。
9. 接下来就是要把刚刚的PayToken拿去问另一支API服务OrderPayQuery来取得该PayToken对应到的付款状态细节。
10. 取得这些资讯後,我们应该要更新电商这笔订单的付款状态,让消费者可透过电商页来确认自己的付款状态确定也是一致的。

简单实作与验证

开发规格书中,针对建立订单交易的虚拟帐号,有以下的必填栏位:

参数名称 说明 我们的内容
ShopNo 商店号码 NA0249_001
OrderNo 订单编号 (由商店产生) ex. A202109123456 (格式固定,但後六码随机动态产生)
Amount 订单总金额需补上小数2位**。所以如果是10元,则Amount是1000。 79900 注:是799元,当然可设计随机产生。
CurrencyID 币别固定传入TWD TWD
PrdtName 收款名称最长60个中英文。 ATM虚拟帐号收款
ReturnURL 将顾客导回付款完成页面之网址 https://127.0.0.1/sinopac/demoSite/payFinished/ (之後再实作)
PayType 收款方式ATM虚拟帐号的话,固定传入A A
ExpireDate 付款截止日使用虚拟帐号为必填,若为2021/9/30,则填入20210930 执行日期+N天

程序实作上会先以验证与正确性为目标,主要把重点先放在发出request与取得response的结果符合预期为主,不会花太多时间在功能模组的设计,後面有时间再慢慢重构程序码。

所以我会先走一遍Hard code版的request资料,之後再把类似OrderNo、Amount、ExpiredDate等值以订单的产生器的方式作模拟,让每次的订单内容都可以有所不同以贴近真实的消费行为。

因此,一样的我们盘点「阶段一」的高阶逻辑後,可大约展出下面的实作关键

  1. 固定值准备:ShopNo、Hash四组代码、产生Hash ID,储存备用
  2. 呼叫API取得Nonce值,储存备用
  3. 动态值准备:订单号码、总金保、虚拟帐号过期日期
  4. 建立订单讯息内文物件,并将上述相关值放入属性中
  5. 功能:处理AES加密流程,产生Message密文
  6. 功能:处理安全签章流程,产生Sign的SHA256
  7. 建立OrderCreate的JSON物件,把上述产生的值放入属性中,以此为request呼叫API
  8. 解析API回传的response,并进行AES解密
  9. 判读回传状态,并取出所需要资料以及处理後续流程

接着就可以开始来准备Python Code的实作了

import urllib
import hashlib
import requests
import json
from Crypto.Cipher import AES 
from Crypto.Util.Padding import pad
import binascii
import datetime
from random import randrange
from datetime import date, timedelta, datetime
程序说明

先引入我们会用到的module,由於我们会需要产生动态乱数的订单号码,所以会引入random module,以及要实作付款到期日,所以也需引入datetime module。

shop_no = "NA0249_001"
A1, A2, B1, B2 = "86D50DEF3EB7400E", "01FD27C09E5549E5", "9E004965F4244953", "7FB3385F414E4F91"
程序说明

上面shop_no与A1~A4的值是固定的,因此就先hard code写在这里。

def bytes_xor_to_hexstring(ba1, ba2):
    return bytes([a ^ b for a, b in zip(ba1, ba2)]).hex()

def get_hash_id():
    ba_xor_A = bytes_xor_to_hexstring(bytes.fromhex(A1), bytes.fromhex(A2))
    ba_xor_B = bytes_xor_to_hexstring(bytes.fromhex(B1), bytes.fromhex(B2))
    return "{}{}".format(ba_xor_A, ba_xor_B).upper()

def get_new_nonce():
    url = "https://sandbox.sinopac.com/QPay.WebAPI/api/Nonce"
    req_param = {
        "ShopNo": shop_no
    }
    response = requests.post(url=url, json=req_param).json()
    return str(response["Nonce"])
    
def get_aes_iv(nonce):    
    return hashlib.sha256(nonce.encode('UTF-8')).hexdigest().upper()[-16:]
    
程序说明

这边准备了几个function主要是将A1~A4 Hash代码进行运算,主要产生Hash ID用途。
另外还有先前最早呼叫的取得nonce值的API。
有了nonce值後,就可以产生AES加密所需要的IV值。
以上可参考之前的文章:
Day03 - [丰收款] 分析技术文件後,开始做个Nonce开胃菜吧!
Day04 - [丰收款] 金流API的起手式,每次沟通都机密

在进行message的加密以及sign安全签章之前,我们这次要模拟每次的订单交易资料都不相同,因此我们要把原本完全hard code的shop_data讯息内文,写一些function来动态产生资料。

明天再继续,先前是将shop_data完全以开发规格书中的资料进行验证,里面的值都是死的,包含nonce值也是固定的。接下来我们将提供较为模拟且每次会不相同的订单资料,然後来实际呼叫API。

  • 产生乱数订单(前面会带入年、月,後面会产生乱码订单号,再依据「客户是否会付款」进行尾码处理)
  • 可设定过期天数产生所需的过期日字串

<<:  Day 09 - Design System x 实作 — Typography

>>:  Day9 Android - Intent(换页)的基础上->A页面传值(bundle)至B页面

冒险村25 - Design Pattern(5) - Service Object

25 - Design Pattern(5) - Service Object Service 相对...

[Day 6 ] 想发表作品,先学会使用 Github 生成静态网页吧!

前言 过去总是羡慕具有设计、美术能力的朋友们,都能累积自己的作品集,并自豪地展现给大众。我的工作属於...

(Day30) - 完结心得

前言 这是本人第一次挑战铁人赛,虽然这篇幅水了不少文章,不过也终於让我写到完赛了 ✧*。 ٩(ˊᗜˋ...

[Day16] MySQL 简介

之前我们在写 API 程序的时候,一开始使用写死在程序里的资料集合(List),这个方法虽然快速让我...

[区块链&DAPP介绍 Day16] Solidity 教学 - libraries

今天来介绍一个 Solidity 的另一个特别的东西 libraries。 下面来看看 librar...