Panduan Pasukan Lucee MY

FPX (PayNet) dari CFML: OAuth2 dan tandatangan RSA

Integrasikan FPX PayNet dari Lucee: dapatkan token OAuth2 client credentials, bina tandatangan RSA atas rentetan medan dan sahkan panggilan balik.

FPX (PayNet) dari CFML: OAuth2 dan tandatangan RSA
0
Kandungan

FPX (PayNet) dari CFML: OAuth2 dan tandatangan RSA

FPX ialah sistem pembayaran antara bank Malaysia yang dikendalikan oleh PayNet, dan ia boleh disambungkan sepenuhnya daripada Lucee tanpa SDK khas. Anda perlukan tiga benda: token OAuth2 untuk mengesahkan panggilan, tandatangan RSA untuk menandatangani mesej, dan cfhttp untuk menghantarnya. Artikel ini menunjukkan ketiga-tiganya dengan kod CFML yang sah pada Lucee 7.1. Satu amaran awal: kredensial sebenar hanya wujud selepas anda lulus onboarding sebagai Merchant atau TPA, jadi kod di sini berpandukan dokumentasi rasmi PayNet dan mesti diuji di UAT dahulu sebelum sebarang transaksi sebenar.

Dua dunia PayNet: FPX klasik dan API REST baharu

Sebelum menulis kod, kenal pasti platform yang anda sambung. Dokumentasi PayNet terbahagi dua. Platform legasi FPX didokumenkan di docs.developer.paynet.my dan berkomunikasi melalui mesej OFX atau XML, contohnya mesej AR untuk Authorization Request. Platform REST baharu didokumenkan di docs.paynet.my dan menggunakan JSON dengan token OAuth2. Kedua-dua halaman boleh dibaca tanpa log masuk, tetapi kredensial dan endpoint hidup untuk kedua-duanya hanya keluar selepas onboarding.

Perbezaan ini penting untuk tandatangan. FPX klasik menandatangani mesej dengan kriptografi asimetri, iaitu tandatangan RSA dengan kunci peribadi anda. Platform REST baharu pula menandatangani permintaan dengan HMAC-SHA256 atas pengepala x-timestamp menggunakan client_secret. Dua mekanisme berbeza, dan mencampurkannya ialah punca ralat yang paling biasa. Artikel ini memfokuskan dua bahagian yang paling kerap tersilap, iaitu OAuth2 pada platform baharu dan tandatangan RSA pada FPX klasik.

Peranan merchant, bank dan agregator

Dalam FPX anda bukan berurusan terus dengan PayNet bagi setiap transaksi. PayNet mengendalikan suis antara bank. Anda sebagai merchant berurusan dengan bank pemeroleh atau agregator, iaitu pihak yang dinamakan Third Party Acquirer atau TPA. Bank pembeli pula memegang akaun yang didebitkan. Tanggungjawab anda hanyalah membina permintaan pembayaran yang ditandatangani betul, menghantar pembeli ke FPX, kemudian menerima dan mengesahkan panggilan balik. Ini juga sebab kredensial FPX tidak boleh didaftar sendiri seperti gerbang lain.

Jika anda baru bermula dan mahukan gerbang pembayaran Malaysia yang boleh didaftar sendiri untuk ujian, ToyyibPay dan Billplz jauh lebih mesra kerana kunci ujiannya boleh diperoleh tanpa pensijilan. FPX memerlukan onboarding yang lebih berat, tetapi ia juga laluan terus ke semua bank utama Malaysia tanpa akaun e-dompet perantaraan. PayNet turut mengendalikan DuitNow QR, yang spesifikasinya awam dan boleh dijana tanpa lesen seperti dalam panduan DuitNow QR.

Aliran FPX: Payment Initiation, Acknowledgement dan arahan bayaran

Aliran klasik FPX berlaku dalam tiga langkah besar. Pertama, Payment Initiation: pelayan anda membina mesej AR, menandatanganinya, dan menghantar pembeli ke halaman FPX melalui borang dengan hidden field bernama mesgToBank. Kedua, Acknowledgement: FPX membalas dan mengarahkan pembeli ke bank pilihan mereka untuk log masuk dan mengesahkan. Ketiga, arahan bayaran: bank mendebit akaun pembeli dan PayNet memulangkan keputusan kepada anda melalui panggilan balik AC, iaitu Authorization Complete.

Panggilan balik AC datang melalui dua saluran. Direct AC ialah host-to-host, iaitu FPX memanggil endpoint anda terus. Indirect AC ialah redirect pelayar, iaitu FPX menghantar pembeli balik ke halaman anda dengan hidden field mesgFromBank. Status dibaca daripada kod respons dalam AC: 00 berjaya, 09 pending, dan 99 pending authorization, manakala selebihnya gagal. Panggilan balik ini ditandatangani RSA, jadi anda mesti mengesahkannya dengan sijil awam FPX, bukan dengan kunci anda sendiri.

Token OAuth2 dengan client credentials

Platform REST baharu mengesahkan panggilan dengan token OAuth2 jenis client_credentials. Anda menukar client_id dan client_secret kepada access_token melalui satu panggilan POST. Endpoint sebenar berbeza mengikut persekitaran, jadi simpannya dalam pemboleh ubah konfigurasi dan bukan ditulis terus dalam kod. Nilai itu datang daripada dokumen onboarding PayNet anda.

<cfscript>
    // Nilai sebenar datang daripada dokumen onboarding PayNet. Jangan hardcode dalam kod.
    variables.cfg = {
        endpointToken: "https://api.paynet.my/oauth/token",
        clientId: "MERCHANT_CLIENT_ID",
        clientSecret: "MERCHANT_CLIENT_SECRET"
    };
</cfscript>

<cfhttp url="#variables.cfg.endpointToken#" method="post" result="tokenResp" timeout="15" throwonerror="false">
    <cfhttpparam type="header" name="Content-Type" value="application/x-www-form-urlencoded">
    <cfhttpparam type="header" name="Accept" value="application/json">
    <cfhttpparam type="formField" name="grant_type" value="client_credentials">
    <cfhttpparam type="formField" name="client_id" value="#variables.cfg.clientId#">
    <cfhttpparam type="formField" name="client_secret" value="#variables.cfg.clientSecret#">
</cfhttp>

<cfscript>
    if (tokenResp.ERROR eq "" and left(tokenResp.statusCode, 3) == "200") {
        token = deserializeJSON(tokenResp.fileContent);
        bearer = token.access_token;
        // token.expires_in lazimnya 3600 saat, simpan dan guna semula
    } else {
        writeLog(file = "fpx", text = "Token gagal: " & tokenResp.statusCode);
    }
</cfscript>

Token yang dipulangkan lazimnya sah 3600 saat dan tiada refresh token, jadi simpan ia dalam skop application dan minta semula hanya apabila hampir tamat. Perhatikan timeout pada cfhttp: panggilan ke PayNet tidak boleh menggantung selama-lamanya, jadi tetapkan nilai yang munasabah dan semak kekunci ERROR sebelum membaca fileContent. Cara penuh mengurus cfhttp, termasuk SSL dan redirect, ada dalam panduan cfhttp.

Tandatangan RSA: apa yang ditandatangani

Tandatangan mesej FPX bukan dibuat atas keseluruhan mesej, tetapi atas medan kunci sahaja. Peraturannya ditetapkan PayNet: ambil nilai medan kunci, isih mengikut nama elemen dalam tertib menaik, kemudian cantum nilai itu dengan aksara paip. Contohnya medan fpx_msgToken, fpx_msgType, fpx_sellerExId dan fpx_version menjadi rentetan seperti 01|BE|EX00002200|7.0 sebelum ditandatangani. Nilai hex hasil tandatangan masuk ke medan X-Signature dalam pengepala atau fpx_checkSum dalam mesej FPX Services.

PayNet mendokumenkan algoritma tandatangan mesej FPX klasik sebagai RSA-SHA1 dengan kunci peribadi anda. Jangan anggap susunan medan atau algoritma ini kekal selama-lamanya: semak dokumen onboarding anda untuk versi spesifikasi terkini, kerana senarai medan kunci dan algoritma boleh berubah. Kod di bawah mengikuti algoritma yang didokumenkan dan mengekalkan algoritma sebagai rentetan supaya mudah ditukar.

Fungsi CFML untuk tanda dan sahkan

Lucee tiada fungsi tandatangan RSA terbina dalam, tetapi anda boleh memanggil Java terus. Corak ini sudah terbukti berjalan pada Lucee 7.1: muat kunci peribadi daripada fail PKCS12, tandatangan dengan Signature, dan kembalikan hex.

<cfscript>
    function binaRentetanTandatangan(required struct medan) {
        var nama = medan.keyArray();
        nama.sort("textnocase");
        var nilai = [];
        for (var n in nama) {
            nilai.append(medan[n]);
        }
        return nilai.toList("|");
    }

    function tandatanganRSA(required string rentetan, required string laluanP12, required string kataLaluan, required string alias) {
        var clsString = createObject("java", "java.lang.String");
        var keyStore = createObject("java", "java.security.KeyStore").getInstance("PKCS12");
        var fis = createObject("java", "java.io.FileInputStream").init(laluanP12);
        keyStore.load(fis, clsString.init(kataLaluan).toCharArray());
        fis.close();
        var kunci = keyStore.getKey(alias, clsString.init(kataLaluan).toCharArray());
        var sig = createObject("java", "java.security.Signature").getInstance("SHA1withRSA");
        sig.initSign(kunci);
        sig.update(clsString.init(rentetan).getBytes("UTF-8"));
        return lcase(binaryEncode(sig.sign(), "hex"));
    }

    function sahkanRSA(required string rentetan, required string tandatanganHex, required string laluanSijil) {
        var clsString = createObject("java", "java.lang.String");
        var cf = createObject("java", "java.security.cert.CertificateFactory").getInstance("X.509");
        var fis = createObject("java", "java.io.FileInputStream").init(laluanSijil);
        var sijil = cf.generateCertificate(fis);
        fis.close();
        var sig = createObject("java", "java.security.Signature").getInstance("SHA1withRSA");
        sig.initVerify(sijil.getPublicKey());
        sig.update(clsString.init(rentetan).getBytes("UTF-8"));
        return sig.verify(binaryDecode(tandatanganHex, "hex"));
    }
</cfscript>

Fungsi sahkanRSA menerima sijil awam dalam format DER X.509, iaitu format fail .cer yang PayNet berikan. Ia membina rentetan yang sama daripada medan panggilan balik dan membandingkan tandatangan. Kalau ia pulang false, jangan proses transaksi itu. Corak mengesahkan panggilan balik ini sama seperti yang dibincangkan dalam panduan webhook tempatan, cuma kriptonya RSA dan bukannya HMAC.

Jadual medan penting

MedanArahPenerangan
grant_typepermintaan tokenNilai tetap client_credentials
client_idpermintaan tokenID klien daripada onboarding PayNet
client_secretpermintaan tokenRahsia klien, jangan sesekali dedahkan
access_tokenrespons tokenToken Bearer, sah lazimnya 3600 saat
fpx_msgTypemesej FPXJenis mesej, contohnya AR, AE atau BE
fpx_msgTokenmesej FPXToken mesej yang unik
fpx_sellerExIdmesej FPXID penjual anda
fpx_checkSummesej FPXTandatangan hex atas medan kunci
mesgToBankborang redirectMesej OFX atau XML dalam hidden field
mesgFromBankpanggilan balikMesej AC dalam hidden field

Soalan Lazim (FAQ)

Bolehkah saya integrasi FPX tanpa akaun peniaga?

Tidak untuk persekitaran hidup. Kredensial hanya keluar selepas onboarding sebagai Merchant atau TPA, dan sijil PKI anda mesti diluluskan PayNet dahulu. Dokumentasi awam boleh dibaca, tetapi ujian sebenar memerlukan kelulusan itu.

Apakah beza X-Signature dan fpx_checkSum?

Kedua-duanya membawa tandatangan yang sama, cuma tempatnya berbeza. X-Signature ialah medan dalam pengepala, manakala fpx_checkSum ialah medan dalam mesej FPX Services. Ikut format yang dikehendaki spesifikasi untuk mesej yang anda hantar.

Kenapa susunan medan mesti ikut spesifikasi PayNet?

Kerana tandatangan dibuat atas rentetan yang susunannya ditentukan PayNet, bukan pilihan anda. Isih mengikut nama elemen menaik dan cantum dengan paip. Kalau susunan berbeza walaupun satu aksara, tandatangan anda tidak akan sah di pihak PayNet.

Adakah RSA-SHA1 masih selamat?

PayNet menetapkan algoritma itu untuk mesej FPX klasik, jadi ia adalah keperluan spesifikasi dan bukannya pilihan anda. Semak dokumen onboarding terkini untuk pengesahan algoritma semasa, kerana ia boleh berubah antara versi.

Bolehkah saya uji tanpa kredensial produksi?

Ya, melalui persekitaran UAT. PayNet menyediakan bank ujian dan simulator FPX, dan UAT menerima sijil self-signed selepas CSR anda diluluskan. Senarai penuh langkah ada dalam bahagian senarai semak di bawah.

Sumber

Senarai semak

Sebelum anda menandakan integrasi FPX selesai, pastikan setiap perkara ini dipenuhi semasa ujian sandbox:

  1. CSR dijana dengan kekunci RSA 2048-bit dan dihantar ke PayNet untuk kelulusan.
  2. Sijil UAT dimuat turun dan kunci peribadi disimpan dalam fail PKCS12 di luar webroot.
  3. Token OAuth2 berjaya dipulangkan dan disimpan dalam skop application.
  4. Rentetan tandatangan diisih menaik dan dicantum dengan paip, tepat mengikut spesifikasi.
  5. Mesej AR berjaya menghantar pembeli ke halaman FPX dan kembali dengan AC.
  6. Tandatangan panggilan balik AC disahkan dengan sijil awam FPX sebelum transaksi diproses.
  7. Kod respons AC dibaca dengan betul, iaitu 00 berjaya dan 09 atau 99 pending.
  8. Semua endpoint disimpan dalam pemboleh ubah konfigurasi, tanpa sebarang URL atau rahsia dalam kod.

Dengan tiga bahagian ini, iaitu token OAuth2, tandatangan RSA dan cfhttp, anda sudah boleh menyambungkan Lucee kepada FPX. Selebihnya ialah mematuhi spesifikasi PayNet yang terkini dan menguji setiap langkah di UAT sebelum naik ke produksi.

0 komen

0 komen

Log masuk untuk menjawab atau memberi komen.

Log masuk