如何实现 Authorize.NET Hosted Payments iFrame &Laravel [英] How to implement Authorize.NET Hosted Payments iFrame & Laravel

查看:20
本文介绍了如何实现 Authorize.NET Hosted Payments iFrame &Laravel的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现 Authorize.NET 提供的官方文档和 github 示例是一堆您不需要的非常混乱的东西.这篇文章是对过去几个小时工作的总结,希望可以帮助到其他人.

本指南假设您不想要收据页面,并且希望在成功付款后自动将用户向前移动.

解决方案

站点后端是 Laravel (PHP),但这里几乎没有 Laravel 特定的内容.

首先要做的是添加 Authorize.NET SDK:

composer 需要授权网/授权网

然后我设置了一个接受订单的托管支付存储库,但您可以随意执行此操作,这会将托管表单令牌返回给准备传递给视图的控制器.

items as $order_item){$payment_amount += $order_item->price;}$billing_address = Address::findOrFail($order->billing_address_id);//API 凭证的通用设置$merchantAuthentication = new MerchantAuthenticationType();$merchantAuthentication->setName(Config::get('yoursite.payment_providers.authorize_dot_net.MERCHANT_LOGIN_ID'));$merchantAuthentication->setTransactionKey(Config::get('yoursite.payment_providers.authorize_dot_net.MERCHANT_TRANSACTION_KEY'));//创建交易$transactionRequestType = new TransactionRequestType();$transactionRequestType->setTransactionType("authCaptureTransaction");$transactionRequestType->setAmount($payment_amount);//创建 Bill To 信息$billto = new CustomerAddressType();$billto->setFirstName($order->billing_first_name);$billto->setLastName($order->billing_last_name);$billto->setAddress($billing_address->address_1);$billto->setCity($billing_address->city);$billto->setState($billing_address->state);$billto->setZip($billing_address->zip);$billto->setCountry($billing_address->country);if(!is_null($order->phone)){$billto->setPhoneNumber($order->phone);}//@todo - 实现用户内容并获取电子邮件//$billto->setEmail("changethis@later.com");$transactionRequestType->setBillTo($billto);//设置托管表单选项$setting1 = new SettingType();$setting1->setSettingName("hostedPaymentButtonOptions");$setting1->setSettingValue("{"text": "Pay Now"}");$setting2 = new SettingType();$setting2->setSettingName("hostedPaymentOrderOptions");$setting2->setSettingValue("{"show": false}");$setting3 = new SettingType();$setting3->setSettingName("hostedPaymentReturnOptions");$setting3->setSettingValue("{"showReceipt" : false }");$setting4 = new SettingType();$setting4->setSettingName("hostedPaymentIFrameCommunicatorUrl");$setting4->setSettingValue("{"url": "https://yoursite.local/checkout/payment/response"}");//构建交易请求$request = new GetHostedPaymentPageRequest();$request->setMerchantAuthentication($merchantAuthentication);$request->setTransactionRequest($transactionRequestType);$request->addToHostedPaymentSettings($setting1);$request->addToHostedPaymentSettings($setting2);$request->addToHostedPaymentSettings($setting3);$request->addToHostedPaymentSettings($setting4);//执行请求$controller = new GetHostedPaymentPageController($request);$response = $controller->executeWithApiResponse(ANetEnvironment::SANDBOX);if (($response == null) && ($response->getMessages()->getResultCode() != "Ok") ){返回假;}返回 $response->getToken();}}

请注意,我已将 showReceipt 设置为 false,并且我提供了另一个名为 hostsPaymentIFrameCommunicatorUrl 的设置.不要忘记hostedPaymentIFrameCommunicatorUrl,否则无论将showReceipt 设置为false,您都会获得收据页面.

hostedPaymentIFrameCommunicatorUrl 必须与您的付款页面位于同一域和同一端口上.

然后在您的视图中您需要添加 iFrame(我的只是坐在页面中,我没有打扰灯箱:

<iframe id="load_payment" class="embed-responsive-item" name="load_payment" width="750" height="900" frameborder="0" scrolling="no"></iframe><form id="send_hptoken" action="https://test.authorize.net/payment/payment" method="post" target="load_payment"><input type="hidden" name="token" value="{{ $hosted_pa​​yment_form_token }}"/></表单>

在同一个视图中,您至少需要加载以下 javascript(我使用 jQuery 并且只实现了一半的 transactResponse 方法,但您明白了):

$(document).ready(function(){window.CommunicationHandler = {};函数 parseQueryString(str) {var vars = [];var arr = str.split('&');变量对;for (var i = 0; i < arr.length; i++) {对 = arr[i].split('=');vars[pair[0]] = unescape(pair[1]);}返回变量;}window.CommunicationHandler.onReceiveCommunication = 函数(参数){console.log('通信处理程序进入');var params = parseQueryString(argument.qstr)开关(参数['动作']){案例调整窗口":console.log('resize');休息;案例successfulSave":console.log('保存');休息;案例取消":console.log('取消');休息;案例交易响应":sessionStorage.removeItem("HPTokenTime");console.log('交易完成');var transResponse = JSON.parse(params['response']);window.location.href = '/checkout/complete';}}//发送令牌$('#send_hptoken').submit();});

上面的代码添加了一个函数来处理从 iFrame Communicator 返回的消息(下一步),并提交支付表单令牌以获取和加载实际的支付表单.

接下来我们需要设置一个iframe 通信器" 这基本上只是 Authorize.NET 绕过 同域源策略

为此,创建一个新路由和一个视图,该视图只返回一个简单的 HTML 页面(或一个刀片模板,但除了脚本之外应该没有其他内容).

<头><title>IFrame Communicator</title><script type="text/javascript">函数 callParentFunction(str) {if (str && str.length > 0 && window.parent.parent&&window.parent.parent.CommunicationHandler &&window.parent.parent.CommunicationHandler.onReceiveCommunication) {var引用者 = document.referrer;window.parent.parent.CommunicationHandler.onReceiveCommunication({qstr : str , parent :referrer});}}函数接收消息(事件){如果(事件&& event.data){callParentFunction(event.data);}}如果(window.addEventListener){window.addEventListener("message", receiveMessage, false);} else if (window.attachEvent) {window.attachEvent("onmessage", receiveMessage);}如果(window.location.hash && window.location.hash.length > 1){callParentFunction(window.location.hash.substring(1));}<body></body>

这里的关键部分是window.parent.parent

Authorize.NET 获取您在开始时提供的 HostedPaymentIFrameCommunicatorUrl,并将其嵌入到另一个 iFrame 中,在他们自己的支付 iFrame 中.这就是为什么它是 window.parent.parent.

您的 hostsPaymentIFrameCommunicatorUrl 脚本然后可以将付款响应传递到您的付款页面,然后您可以编辑上述功能以执行您喜欢的操作.

希望对某人有所帮助.

Authorize.NET 严重缺乏示例,他们的文档充其量只是轻量级的.让您筛选大量不需要的代码的包罗万象"示例只是懒惰.

他们的 API 文档还不错,他们只需要像样的例子......

I found the official documentation and the github example provided by Authorize.NET to be a terribly confusing mess of stuff you don't need. This post is a summary of the last few hours work hoping it may help others.

This guide assumes you don't want the receipt page and you want to automatically move the user forward on successful payment.

解决方案

The site back-end is Laravel (PHP) but there's little in here that's Laravel specific.

First thing to do is add the Authorize.NET SDK:

composer require authorizenet/authorizenet

I then setup a hosted payments repository that accepts the order but you could do this however you like, this returns the hosted form token to a controller ready to pass to the view.

<?php

namespace ShopAppRepositories;
use ShopAppModelsOrder;
use ShopAppRepositoriesContractshostedPaymentRepositoryContract;
use IlluminateSupportFacadesConfig;
use netauthorizeapicontractv1MerchantAuthenticationType;
use netauthorizeapicontractv1TransactionRequestType;
use netauthorizeapicontrollerGetHostedPaymentPageController;
use netauthorizeapicontractv1GetHostedPaymentPageRequest;
use netauthorizeapicontractv1SettingType;
use netauthorizeapiconstantsANetEnvironment;
use netauthorizeapicontractv1CustomerAddressType;
use ShopAppModelsAddress;

/**
 * Class hostedPaymentRepository
 * @package ShopAppRepositories
 * @todo - Implement methods to talk to Authorize.NET and show form.
 */

class hostedPaymentRepository implements hostedPaymentRepositoryContract
{

    public $response; //what did we get back?
    public $paymentFormToken;

    public function getHostedFormToken(Order $order){

        $payment_amount = null;

        foreach($order->items as $order_item){

            $payment_amount += $order_item->price;

        }

        $billing_address = Address::findOrFail($order->billing_address_id);

        // Common setup for API credentials
        $merchantAuthentication = new MerchantAuthenticationType();
        $merchantAuthentication->setName(Config::get('yoursite.payment_providers.authorize_dot_net.MERCHANT_LOGIN_ID'));
        $merchantAuthentication->setTransactionKey(Config::get('yoursite.payment_providers.authorize_dot_net.MERCHANT_TRANSACTION_KEY'));

        //create a transaction
        $transactionRequestType = new TransactionRequestType();
        $transactionRequestType->setTransactionType("authCaptureTransaction");
        $transactionRequestType->setAmount($payment_amount);

        // Create the Bill To info
        $billto = new CustomerAddressType();
        $billto->setFirstName($order->billing_first_name);
        $billto->setLastName($order->billing_last_name);
        $billto->setAddress($billing_address->address_1);
        $billto->setCity($billing_address->city);
        $billto->setState($billing_address->state);
        $billto->setZip($billing_address->zip);
        $billto->setCountry($billing_address->country);

        if(!is_null($order->phone)){

            $billto->setPhoneNumber($order->phone);

        }

        //@todo - implement user stuff and get email
        //$billto->setEmail("changethis@later.com");

        $transactionRequestType->setBillTo($billto);

        // Set Hosted Form options
        $setting1 = new SettingType();
        $setting1->setSettingName("hostedPaymentButtonOptions");
        $setting1->setSettingValue("{"text": "Pay Now"}");

        $setting2 = new SettingType();
        $setting2->setSettingName("hostedPaymentOrderOptions");
        $setting2->setSettingValue("{"show": false}");

        $setting3 = new SettingType();
        $setting3->setSettingName("hostedPaymentReturnOptions");
        $setting3->setSettingValue("{"showReceipt" : false }");

        $setting4 = new SettingType();
        $setting4->setSettingName("hostedPaymentIFrameCommunicatorUrl");
        $setting4->setSettingValue("{"url": "https://yoursite.local/checkout/payment/response"}");


        // Build transaction request
        $request = new GetHostedPaymentPageRequest();
        $request->setMerchantAuthentication($merchantAuthentication);
        $request->setTransactionRequest($transactionRequestType);

        $request->addToHostedPaymentSettings($setting1);
        $request->addToHostedPaymentSettings($setting2);
        $request->addToHostedPaymentSettings($setting3);
        $request->addToHostedPaymentSettings($setting4);

        //execute request
        $controller = new GetHostedPaymentPageController($request);
        $response = $controller->executeWithApiResponse(ANetEnvironment::SANDBOX);

        if (($response == null) && ($response->getMessages()->getResultCode() != "Ok") )
        {
            return false;
        }

        return $response->getToken();
    }

}

Note that I have set showReceipt to false and I have offered another setting called hostedPaymentIFrameCommunicatorUrl. Do not forget the hostedPaymentIFrameCommunicatorUrl otherwise you will get the reciept page regardless of setting showReceipt to false.

The hostedPaymentIFrameCommunicatorUrl MUST be on the same domain as your payment page and on the same port.

Then in your view you need to add the iFrame (mine just sits in the page, i didn't bother with the lightbox:

<div id="iframe_holder" class="center-block" style="width:90%;max-width: 1000px" data-mediator="payment-form-loader">
    <iframe id="load_payment" class="embed-responsive-item" name="load_payment" width="750" height="900" frameborder="0" scrolling="no">
    </iframe>

    <form id="send_hptoken" action="https://test.authorize.net/payment/payment" method="post" target="load_payment">
        <input type="hidden" name="token" value="{{ $hosted_payment_form_token }}" />
    </form>

</div>

In the same view you need to load at least the following javascript (im using jQuery and have only half implemented the transactResponse method, but you get the idea):

$(document).ready(function(){

    window.CommunicationHandler = {};

    function parseQueryString(str) {
        var vars = [];
        var arr = str.split('&');
        var pair;
        for (var i = 0; i < arr.length; i++) {
            pair = arr[i].split('=');
            vars[pair[0]] = unescape(pair[1]);
        }
        return vars;
    }

    window.CommunicationHandler.onReceiveCommunication = function (argument) {

        console.log('communication handler enter');

        var params = parseQueryString(argument.qstr)

        switch(params['action']){
            case "resizeWindow"     :

                console.log('resize'); break;

            case "successfulSave"   :

                console.log('save'); break;

            case "cancel"           :

                console.log('cancel'); break;

            case "transactResponse" :

                sessionStorage.removeItem("HPTokenTime");

                console.log('transaction complete');

                var transResponse = JSON.parse(params['response']);

                window.location.href = '/checkout/complete';

        }
    }

    //send the token
    $('#send_hptoken').submit();


});

The above code adds a function to handle the message that comes back from the iFrame Communicator (next step) and also submits the payment form token to get and load the actual payment form.

Next we need to setup an 'iframe communicator' This is basically just a way for Authorize.NET to get around the same-domain origin policy

To do this, create a new route and a view that just returns a simple HTML page (or a blade template, but it should have no content other than the scripts).

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>IFrame Communicator</title>
    <script type="text/javascript">

    function callParentFunction(str) {

        if (str && str.length > 0 && window.parent.parent
            && window.parent.parent.CommunicationHandler && window.parent.parent.CommunicationHandler.onReceiveCommunication) {

            var referrer = document.referrer;
            window.parent.parent.CommunicationHandler.onReceiveCommunication({qstr : str , parent : referrer});

        }

    }

    function receiveMessage(event) {

        if (event && event.data) {
            callParentFunction(event.data);
        }

    }

    if (window.addEventListener) {

        window.addEventListener("message", receiveMessage, false);

    } else if (window.attachEvent) {

        window.attachEvent("onmessage", receiveMessage);

    }

    if (window.location.hash && window.location.hash.length > 1) {

        callParentFunction(window.location.hash.substring(1));

    }

</script>
</head>
<body></body>
</html>

The key part here is the window.parent.parent

Authorize.NET grabs your hostedPaymentIFrameCommunicatorUrl that you gave it in the beginning and embeds this within another iFrame, inside their own payment iFrame. Which is why it's window.parent.parent.

Your hostedPaymentIFrameCommunicatorUrl script then can pass the payment response to your payment page and you can edit the functions above to do what you like after that.

Hope that helps someone.

Authorize.NET is seriously lacking examples and their docs are lightweight at best. The 'catch-all' example that has you sifting through loads of code you don't need is just plain lazy.

Their API doc isn't bad though, they just need decent examples...

这篇关于如何实现 Authorize.NET Hosted Payments iFrame &amp;Laravel的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆