智付通金流整合

今年初用 rails 做了個系統與智付通的金流整合。整合過程其實蠻單純的,稍微將實做整合的過程記錄在這邊。

當初整合智付通的流程是,使用者在我站挑選要購買的商品後,到結帳頁面輸入送貨地址,是否要開索取發票,是否使用折價卷或點數扣抵等等資訊。後。將使用者與確認完整的購買資訊 POST 到智付通的付款頁面。待使用者付款完成後,智付通會將使用者再導回我站,並且傳回付款結果等資訊告知我站是否已成功付款;同時背景也會呼叫我站的 Notify URL。

spgateway-integration

大概整合內容如上,很簡單。

幾個整合的重點:

  • 跳轉到智付通的頁面要用 Form POST 把玩家導過去,要整頁導過去。智付通文件有說明放 iframe 裡導頁會有問題。
  • 智付通回饋付款結果有兩個
    • ReturnURL (前景) 讓使用者在付款完後(不管成功失敗) 導回 ReturnURL
    • NotifyURL (背景) 會在背景把支付完後的資訊打給 NotifyURL
  • 加解密的方式

這邊遇到一點問題的就是加解密,所以說明一下。其他頁面跳轉大部分的金流好像都差不多。

加解密的方式

整個加密重點在這段,智付通的 API 文件上提供 mcrypt_encrypt(CRYPT_RIJNDAEL_128, key, CRYPT_MODE_CBC, iv) (PHP) 與 RijndaelManaged() (.NET) 的 AES 加密範例可參考。

用 ruby 有遇到一點麻煩,因為先參考了mcrypt 的範例,一開始就直接用 OpenSSL 來加密,但是 encrypt 出的字串與智富通的不合。參考這篇 Stack Overflow 的答案  可知,在 ruby 裡用 OpenSSL::Cipher 與 mcrypt 執行起來的行為是不一樣的。將 256 bit 的 key 傳入 mcrypt( ) 他會自己改為 rijndael-256 的編碼,而 OpenSSL::Cipher 只會拿前 128 bits 。

而智付通給的key 是 256 bits 的

權衡之下,還是用了 php-mcrypt ….讓 mcrypt 自己去調整編碼方式

# 這個 hash 轉成 QUERY STRING 涵式是這邊抄來的: 
# https://justanothercoder.wordpress.com/2009/04/24/converting-a-hash-to-a-query-string-in-ruby/
payload_str = Common::hash_to_querystring(@payload)

# 加密 payload
crypto = Mcrypt.new(:rijndael_128, :cbc, key, iv, :pkcs)
ciphertext = crypto.encrypt(payload_str)

ciphertext.unpack("H*").join()

最後,組出單向的核對字串:

def trade_sha(tradeInfo)
    key = Settings.payment.spgateway.key
    iv = Settings.payment.spgateway.iv

    Digest::SHA256.hexdigest("HashKey=#{key}&#{tradeInfo}&HashIV=#{iv}").upcase
end

完整的加密 Gist

在智付通把使用者導回 ReturnURL 的時後同時也會送來一串交易結果的 payload,這個 payload 的解密方式如下

def decrypt
    key = Settings.payment.spgateway.key
    iv = Settings.payment.spgateway.iv

    crypto = Mcrypt.new(:rijndael_128, :cbc, key, iv)
    plaintext = crypto.decrypt([@payload].pack('H*'))

    # 移除解密後多出來的 padding
    # 因為知道加密的內容是 JSON 所以可以用這樣的懶惰方式移除 padding...
    plaintext[0, plaintext.rindex('}') + 1]
  end

記得好像就醬,目前好像開立電子發票,信用卡請款等等都可用上述的方式加解密。整合來說並不算太複雜。

複雜的反而是開電子發票後如果客人要退貨,依照相關法規要退發票重新申報這些。如果可以直接進智付通後台操作那就還好…不然靠 API 要弄電子發票真的很繁雜….