Flask-第三方金流串接實作(綠界)

Johney Chen
7 min readOct 22, 2023

--

在購物網站中,常使用第三方金流作為消費者支付的方式,在此紀錄在綠界上測試API的實作過程。
參考資料 : https://www.maxlist.xyz/2020/02/14/python-ecpay/

前置 :

若於本地IP執行測試,會沒辦法接收到綠界所回傳的訂單資訊,此時可使用Ngrok 開放自己的網域。https://ngrok.com/download
下載完畢後,開啟ngrok,輸入 ngrok http 5000 (或是你的port)
可暫時獲得公開IP,供測試使用。

Ngrok

Step 1 : 點擊觸發綠界輸入頁面

  1. 撰寫Restful API 處理 Request
# router
@allRoute.post('/account/create_payment') #用戶儲值
def Accountdeposit(): return UserController().Accountdeposit()

# Controller
amount = data.get("amount")
account = data.get("account")
customername = data.get("customername")
result = self.PaymentService.Accountdeposit(user_id,amount,account,customername)

2. 將參數傳入由綠界提供的API文件及範例, returnURL 記得填寫 ngrok 指定的位置。

# PaymentService
def Accountdeposit(self,user_id,amount,account,customername):
# 由綠界公開GitHub可查詢相關文件代碼
....
# returnURL 記得填寫 ngrok 指定的位置
'ReturnURL': 'https://906f-122-118-50-103.ngrok-free.app/api/account/receive_result',

html = ecpay_payment_sdk.gen_html_post_form(action_url, final_order_params)
return html

3. 渲染該html所需的資料,產生綠界網站

# Controller
result = render_template('payment.html', form_html=result)
綠界支付畫面

Step 2: 輸入模擬轉帳,回傳訂單資訊

於信用卡處輸入模擬轉帳使用之信用卡與OTP,不用點選測試鈕,直接在下方輸入該資訊即可測試。

卡號 : 4311–9522–2222–2222

有效年月 : 大於當前日期

安全碼 : 222

OTP : 1234

信息填寫

當送出OTP後,綠界會根據ReturnURL所填寫的API,將訂單資訊回傳。

'ReturnURL': '/api/account/receive_result'

# router
@allRoute.post('/account/receive_result') #處理儲值結果
def Receiveresult(): return UserController().Receiveresult()

此時必須檢查CheckMacValue,確保該訂單的正確性,沒有被竄改或是他人任意打這支API想搞破壞。將訂單的資訊轉化成CheckMacValue,需透過以下步驟 :

  1. 將傳遞參數依照字母排序
  2. 參數最前面加上 HashKey、最後面加上 HashIV
  3. 進行 URL encode
  4. 轉為小寫
  5. 以 SHA256 加密方式來產生雜凑值
  6. 再轉大寫產生 CheckMacValue

官方文檔:https://developers.ecpay.com.tw/?p=2902

參考網站 :https://www.maxlist.xyz/2020/02/14/python-ecpay/

# Controller

check_mac_value = self.PaymentService.get_mac_value(request.form)

# PaymentService
def get_mac_value(self,get_request_form): # 把訂單的資訊轉化成check_mac_value
params = dict(get_request_form)
if params.get('CheckMacValue'):
params.pop('CheckMacValue') #提取出CheckMacValue

# step 1
ordered_params = (sorted(params.items(), key=lambda k: k[0].lower()))
# step 2 (官網有給測試用Key,IV)
HahKy = 'pwFHCqoQZGmho4w6'
HashIV = 'EkRm7iFT261dpevs'
encoding_lst = []
encoding_lst.append('HashKey=%s&' % HahKy)
encoding_lst.append(''.join([
'{}={}&'.format(key, value)
for key, value in ordered_params
]))
encoding_lst.append('HashIV=%s' % HashIV)
# step 3,4
safe_characters = '-_.!*()'
encoding_str = ''.join(encoding_lst)
encoding_str = quote_plus(str(encoding_str),
safe=safe_characters).lower()
# step 5,6
check_mac_value = ''
check_mac_value = hashlib.sha256(
encoding_str.encode('utf-8')).hexdigest().upper()
return check_mac_value

完成check_mac_value後,即可將訂單資訊放入進行比對,判斷訂單正確性,來編寫後續的操作方式。

check_mac_value = self.PaymentService.get_mac_value(request.form)
if request.form['CheckMacValue'] == check_mac_value:
result = self.UserService.Receiveresult(dto) ## 比對通過,進行商業邏輯
print('test passed')
else:
return make_response(jsonify({
"success":False,
"message":str('CheckMacValue Failed')
## 比對失敗,處理訂單失敗邏輯
}),400)

從綠界支付系統接收到包含 CheckMacValue 的訂單資訊。

使用相同的密鑰和演算法,在本地計算訂單資訊的 CheckMacValue

比較計算的 CheckMacValue 和綠界支付系統提供的 CheckMacValue。如果它們匹配,則表示訂單資訊在傳輸過程中未被篡改。

--

--