# Apple Pay on Web 串接
最近要為網站加上 Apple Pay 付款,從申請 Apple 憑證開始,到網站串接 Apple Pay SDK ,最後再串接藍新、綠界的 API 完成整套的 Apple Pay 付款流程,這篇紀錄一下整個過程以及一些筆記,希望可以幫助到大家。
# 申請 Merchant ID
登入 Apple Developer
進入 Certificates, Identifiers & Profiles
進入 Identifiers 新增 Merchant ID
新增 Merchant ID
填寫 Merchant ID
Description
可以隨便寫,Identifier
建議將 domain 反過來寫以確保唯一, Apple 會再加上merchant.
的前綴確定就按下 Register
回到 Identifiers ,剛剛設定的 Merchant ID 就已經設定好了
# 驗證 Merchant Domain
進入剛剛設定的 Merchant Identifiers ,在 Merchant Domains 按下 Add Domain
接著就填要使用 Apple Pay 的 domain
接著就會產出一個
apple-developer-merchantid-domain-association.txt
檔案,將這個檔案下載下來放在https://domain/.well-known/apple-developer-merchantid-domain-association.txt
給 Apple 驗證驗證成功後就可以看到 Merchant Domains 已經是綠色的 Verified 的狀態,另外 Verification Expires 會是 SSL 憑證到期日,所以用 Let's Encrypt 的憑證就是三個月內就會到期,建議可以買付費的憑證,這樣就可以撐一年了,至於買 SSL 憑證院長唯一推薦 GoGetSSL (opens new window) 這個網站
# 申請 Merchant identity certificate
接著就是要申請 Merchant Identity Certificate ,這個憑證是用來啟用 merchant session 用的,在網頁上使用者要發動 Apple Pay 時會使用這個憑證跟 Apple 要一個 merchant session 回來,這樣才能進行接下來的 Apple Pay 付款,詳細可以看這邊
申請 Merchant Identity Certificate
產生 CSR(Certificate Signing Request)
因為 Mac 上的憑證製作器實在很難用,所以院長都是用 OpenSSL 的指令來產生。
openssl req -new -newkey rsa:2048 -nodes -keyout apple_pay_merchant_id.key -out apple_pay_merchant_id.csr
上傳 CSR
下載產生後的證書 cer 檔
轉成 pem 備用
openssl x509 -inform der -in apple_pay_merchant_id.cer -out apple_pay_merchant_id.cer.pem
# 申請 Payment processing certificate
再來就是申請 Payment processing certificate ,這個憑證可以解開 Apple Pay token ,如果是串接第三方金流公司(藍新、綠界之類的),申請完把憑證跟 Key 給金流公司就好,金流公司會處理解開 Apple Pay token 的工作。
如果是串接銀行就要自己用這個憑證把 Apple Pay token 解開,再把解開的 payload 傳給銀行,這邊其實還蠻麻煩的,詳細可以參考 輕鬆解密 Apple pay payment token. (跳過第三方金融服務商串接 Apple Pay ) (opens new window) 這篇文章。
申請 Payment processing certificate
詢問是否要用在中國,如果要就選 Yes, 不用就選 No,好像是之後產生 CSR 時要使用不同的演算法
產生 CSR(Certificate Signing Request)
一樣用 OpenSSL 的指令來產生,不過這邊的演算法就要用 ECC(256)的演算法。
openssl ecparam -out apple_pay_payment.key -name prime256v1 -genkey
openssl req -new -sha256 -key apple_pay_payment.key -nodes -out apple_pay_payment.csr
上傳 CSR
下載產生後的證書 cer 檔
申請完就把這個憑證 cer 檔跟 Key 給第三方金流公司
# 網頁程式整合
# 測試環境
- 瀏覽器一定要用 Safari
- 網址一定要是 https
- localhost 如何生成 SSL 憑證可以參考 極速打造 https://localhost (opens new window) 這篇文章
- 用自己的信用卡測試,測試環境不會扣款
# 程式碼哪裡抄
Apple Pay on the Web Demo (opens new window) 下面有 Show Source 的分頁,裡面的 code 抄起來。
# 定義 ApplePayPaymentRequest
// Define ApplePayPaymentRequest
const request = {
'countryCode': 'TW',
'currencyCode': 'TWD',
'merchantCapabilities': [
'supports3DS'
],
'supportedNetworks': [
'visa',
'masterCard',
'jcb'
],
'total': {
'label': '商店名稱',
'type': 'final',
'amount': amount
}
}
主要改 supportedNetworks
這邊的設定,台灣的話只要支援 visa
, masterCard
, jcb
就可以了,更多可以參考 Apple Pay 的文件 (opens new window) 。
再來是改 total.amount
欄位,改成付款的總金額。這邊要注意,金額最好從後端算好傳到前端避免傳輸或是計算過程被篡改。
# 實作 onvalidatemerchant
session.onvalidatemerchant = async event => {
// Call your own server to request a new merchant session.
const res = await fetch('/api/validateMerchant', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ validationURL: event.validationURL })
})
const data = await res.json()
if (data.status === 'success') {
session.completeMerchantValidation(data.merchantSession)
} else {
session.completeMerchantValidation({
'status': ApplePaySession.STATUS_FAILURE
})
}
}
這個步驟是要驗 Merchant ,將 event.validationURL
傳到 API server ,從 API server 發 request 取得 merchantSession
# API 端
const apple_merchant_id_agent = new https.Agent({
cert: fs.readFileSync(`../credential/apple_pay_merchant_id.cer.pem`),
key: fs.readFileSync(`../credential/apple_pay_merchant_id.key`)
})
api.post('/validateMerchant', async (ctx) => {
return axios.post(ctx.request.body.validationURL, {
merchantIdentifier: 'merchant.com.example.mystore',
displayName: 'MyStore',
initiative: 'web',
initiativeContext: 'mystore.example.com',
}, { httpsAgent: apple_merchant_id_agent }).then((body) => {
return ctx.body = {
status: 'success',
merchantSession: body.data
}
}).catch((err) => {
return ctx.body = {
status: 'error'
}
})
})
API 端這邊就是向 validationURL
發 post 取得 merchantSession
, merchantIdentifier
跟 initiativeContext
要跟 申請 Merchant ID 這邊的設定一樣。
displayName
可以中文,基本上就是填網站名稱, initiative
固定帶 web
最後 axios 還要設定 https.Agent
,把之前 申請的 Merchant identity certificate 附上去。
# 刪掉無用的 handler
onpaymentmethodselected
, onshippingmethodselected
, onshippingcontactselected
這三個 handler 可以註解或是刪掉,這是讓你在結帳流程時如果有改變付款方式、寄送方式、寄送地址時呼叫的,用意是在這三個階段改變金額用的。
基本上沒啥用,因為一般的流程這些都會在按下 Pay with Apple Pay 按鈕前就就會計算好總金額。
# 實作 onpaymentauthorized
session.onpaymentauthorized = event => {
// Define ApplePayPaymentAuthorizationResult
const res = await fetch(`/api/apple_pay`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
token: event.payment.token.paymentData
})
})
const res = await res.json()
if (res.status === 'success') {
const result = {
'status': ApplePaySession.STATUS_SUCCESS
}
session.completePayment(result)
} else {
const result = {
'status': ApplePaySession.STATUS_FAILURE
}
session.completePayment(result)
}
}
這個步驟可以透過 event.payment
取得 payment token ,那藍新只要 payment.token.paymentData
就可以,所以就只要傳 token 到 API server 就可以了。
# API 端
api.post('/apple_pay', async (ctx) => {
const payload = {
TimeStamp: Math.round(Date.now() / 1000),
Version: '1.1',
MerchantOrderNo: merchant_order_no,
Amt: Big(amount),
APPLEPAY: ctx.request.body.token
APPLEPAYTYPE: '02'
ProdDesc: 'Apple Pay 付款'
}
const postdata = (new URLSearchParams({
MerchantID_: merchant_id,
PostData_: toNewebPayPostData(key, iv, payload),
Pos_: 'JSON'
})).toString()
const { data } = await axios.post('https://core.newebpay.com/API/CreditCard', postdata)
if (data.Status === 'SUCCESS') {
ctx.body = {
status: 'success'
}
} else {
ctx.body = {
status: 'error'
}
}
})
API 這邊就看藍新的 API 文件把 token 跟其他必要的參數 POST 到付款的 endpoint ,再根據回傳的 status 將結果回傳給網頁前端。
# 實作 oncancel
session.oncancel = event => {
alert('取消付款或付款失敗')
}
取消付款或是付款失敗會呼叫 oncancel
這個 handler ,就在這邊 handle 錯誤。
# Apple Pay 按鈕
Apple Pay 按鈕有嚴格的規範,最好是用 Apple Pay on the Web Demo (opens new window) 裡面 Display an Apple Pay button 這邊的產生器來產生下面的 Apple Pay 按鈕程式碼
<style>
apple-pay-button {
--apple-pay-button-width: 150px;
--apple-pay-button-height: 30px;
--apple-pay-button-border-radius: 3px;
--apple-pay-button-padding: 0px 0px;
--apple-pay-button-box-sizing: border-box;
}
</style>
<apple-pay-button buttonstyle="black" type="plain" locale="en"></apple-pay-button>
上面的程式碼有用到 Web Component ,如果你的開發環境沒辦法使用 Web Component (像院長用的 Marko (opens new window) 這個樣版引擎就不支援 Web Component ),可以參考 Displaying Apple Pay Buttons Using CSS (opens new window) 這篇文章用 CSS 的方式來 style Apple Pay button 。
另外,如果要完全自己畫的話,要參考 Buttons and Marks (opens new window) 的規範。
# 結語
網站導入 Apple Pay 之後,有滿多使用者使用 Apple Pay 結帳付款的,流程也比起傳統要跳轉藍新公司網頁結帳或是傳統銀行 3D 驗證來的流暢許多,雖然導入的步驟比較多也比較複雜,但是總得來說還是利大於弊的。
# 參考資料
- 輕鬆解密Apple pay payment token. (跳過第三方金融服務商串接Apple Pay) | by Ken Chen | Medium (opens new window)
- Command Line Apple Pay CSR's (opens new window)
- Generate an Apple Pay CSR with OpenSSL | Ryan Daigle (opens new window)
- Apple Pay Configuration | Subscribe Pro Magento 1 Extension | Subscribe Pro Documentation (opens new window)
- Apple Pay介接技術文件 | 綠界科技 ECPay (opens new window)