iT邦幫忙

2023 iThome 鐵人賽

DAY 29
0
SideProject30

用 Rails 打造你的電商網站系列 第 29

Day 29 - 開始收錢錢

  • 分享至 

  • xImage
  •  

前置作業:付款資訊的 model 以及 controller / 付款成功及失敗頁面

今天做完就差不多串接好金流了!

設定付款成功後的導向頁面

還記得我們在設定 info 參數的時候,有個叫做 ReturnURL 的參數嗎

這個參數會在消費者付款成功的時候,導回我們的網站(但如果你想導別的網站也是行)

但藍新禁止 ReturnURL 為 127 開頭

我們可以用 ngrok 來做

設定 ngrok

安裝及設定可以參考官方網站

官方寫得很清楚且很容易做

不過我們在 Rails 還需要多設定

Rails 為了防止 DNS 攻擊,所以多做了一層防護

我們要設定哪些網域可以存取專案

config.hosts << "ngrok 的網域"

設定完畢後再重開 server

接下來我們就要繼續設定金流了

設定付款後導回的路徑

# app/service/newebpay.rb

def set_info(order)  
  ...
  
  info[:ReturnURL] = "ngrok 網域/orders/newebpay_return"
  
  ...
end

跨網域 CSRF

CSRF 是一種攻擊,用惡意連結或者網站來侵害使用者,

為了防止這種攻擊,Rails 使用 authenticity token 來保護

藍新導回網站的時候,因為是跨網域,不會有正確的 authenticity token

所以需要去 skip 這個保護機制

class OrdersController < ApplicationController
  skip_before_action :verify_authenticity_token, only: [:newebpay_return]


  def newebpay_return
  end
end

解密資料初始化設定

當消費者付款成功時,藍新會傳一包資料回來,不過那包資料也是加密過的

所以我們必須將它解密,並且把部分資料存到資料庫當中

先來做初始化的設定

一樣需要 Hash Key 以及 Hash IV

接著要來將 params (藍新傳過來的那包) 解密

# app/service/newebpay_result.rb

class NewebpayResult
  def initialize(params)
    @key = ENV["HASH_KEY"]
    @iv = ENV["HASH_IV"]

    response = decrypy(params)
  end
end

開始解密

根據官方手冊說明,藍新會回傳幾個資料

Status 付款成功與否
MerchantID 商店 ID
TradeInfo 交易資料 (以 AES 加密)
TradeSha 交易資料 (以 TradeInfo 再用 SHA256 加密)

我們需要的資料應該都放在 TradeInfo 的 Result 中

現在就來解密吧

# app/service/newebpay_result.rb

class NewebpayResult

  def decrypy(raw_data)
    # 將十六進位轉換為二進位
    encrypted_data = [raw_data].pack('H*')

    # 用 AES 方式解除雜湊
    decipher = OpenSSL::Cipher::AES256.new(:CBC)

    # 設定 decipher 為解密模式
    decipher.decrypt

    # 加解密模式中的一種為了滿足資料長度的填充技術
    decipher.padding = 0

    # 將 @key 及 @iv 塞進 decipher
    decipher.key = @key
    decipher.iv = @iv

    # 開始解密
    data = decipher.update(encrypted_data) + decipher.final
  
    # 移除數據的填充
    plain = data.strip
    if plain[-1] != '}'
      plain = plain[0, plain.index(plain[-1])]
    end

    # 返回資料
    JSON.parse(plain)
  end
end

取得我們要的資料

初始化返回 response

# app/service/newebpay_result.rb

class NewebpayResult
  attr_reader :response

  def initialize(params)
    @key = ENV["HASH_KEY"]
    @iv = ENV["HASH_IV"]

    @response = decrypy(params)
  end
end

controller 接下 response 並且做出 payment

# app/controllers/orders_controller.rb

class OrdersController < ApplicationController
  def newebpay_return
   
    response = NewebpayResult.new(params[:TradeInfo]).response

    if response["Status"] != "SUCCESS"
      redirect_to root_path, notice: '付款失敗'
    else
      response = response["Result"]
      order = Order.find_by(slug: response["MerchantOrderNo"])
      user = order.user

      @payment = Payment.create(order:, user:, amount: response["Amt"], paid_at: response["PayTime"], trade_no: response["TradeNo"])
    end
end

以上就差不多串好金流了,如果要做更細緻的話,各位可以再查藍新的手冊


上一篇
Day 28 - 準備掏錢的前奏
下一篇
Day 30 - 部署
系列文
用 Rails 打造你的電商網站30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言