为什么 "Check version" 步骤的实现仍然失败?

Why this implementation for "Check version" step is still failing?

阅读 3DSecure GlobalPay documentation 后,我的团队选择通过 JSON 与我们自己的 client-side 实施进行集成,因为我们已经在生产中与另一个 3DS 验证服务进行了另一个集成。值得一提的是,我们正在使用 Vue.JS 和 Laravel.

来实现它

从他们的文档中可以看出,GlobalPay 示例请求是:

curl https://api.sandbox.globalpay-ecommerce.com/3ds2/protocol-versions
-H "Content-type: application/json"
-H "X-GP-VERSION: 2.2.0"
-H "Authorization: securehash 0204a841510d67a46fbd305a60253d7bade32c6e"
-X POST
-d '{
   "request_timestamp": "2019-07-30T08:41:07.590604",
   "merchant_id": "MerchantId",
   "account_id": "internet",
   "number": "4263970000005262",
   "scheme": "VISA",
   "method_notification_url": "https://www.example.com/dsNotificationUrl"
}'

我们在 Vue.JS 组件中创建了一个方法来向此版本检查端点发出 POST 请求,您可以在此处看到:

methods: {
    verifyTds(price) {
        this.setTdsAuth(price);
    },
    setTdsAuth() {
        let uri = window.tds.globalPay.checkVersion; // https://api.sandbox.globalpay-ecommerce.com/3ds2/protocol-versions

        let tdsHeaders = {
            'X-GP-Version': '2.2.0',
            'Content-Type': 'application/json',
            'Authorization': `securehash ${this.billing.threeDs.hash}` // from backend, see below
        };

        let tdsParams = {
            request_timestamp: this.billing.threeDs.timestamp, // from backend, see below
            merchant_id: "mymerchantid", 
            account_id: "myaccountid",
            number: parseInt(this.billing.threeDs.pan), // integer, a VISA card from their test cards list: 4263970000005262
            scheme: "VISA", // at this moment, hardcoded, I just want to make it work
            method_notification_url: window.tds.globalPay.methodNotification // in my case http://website.test/tds/global-pay/method-notification, we created according their sample in the docs too
        };

        axios.post(uri, { body: tdsParams }, { headers: tdsHeaders }).then(response => {
            console.log(response);
            // then finish purchase process
        }).catch(error => {
            console.log(error); // then handle error
        });
    },
    // ...
}

如果这个请求是正确的,我们为 Authorization header 生成的 securehash 是在我们的后端(PHP)根据这个计算的:

<?php
// ...    
$globalPayMerchantId = 'mymerchantid';
$globalPaySecret = 'mysecret';

$timestamp = Carbon::now()->toDateTimeLocalString();
$requestTimestamp = Carbon::now()->format('YmdHisu');
$requestHashNoSecretStr = "{$requestTimestamp}.{$globalPayMerchantId}.{$billing->threeDs->pan}";
$requestHashNoSecret = sha1($requestHashNoSecretStr);
$requestHashStr = "{$requestHashNoSecret}.{$globalPaySecret}";
$requestHash = sha1($requestHashStr);

$billing->threeDs->hash = $requestHash; // sth like 6200480999455e596ad3dfdb89b0a1db601e9216
$billing->threeDs->requestTimestamp = $requestTimestamp; // 20210127155812886962
$billing->threeDs->timestamp = $timestamp; // 2021-01-27T15:58:12

我们基本上尝试遵循 GlobalPay 文档 this part 的“如何构建请求哈希”部分的说明。

毕竟,我们只是失败了ERR_CONNECTION_RESET。我已经尝试过不同的浏览器(Firefox、Chrome、Brave),但它总是崩溃。在 Postman 中模拟时,它会产生 415 HTTP 响应(不支持的媒体类型)。

除了仔细检查我们的凭据(merchantid 等,我仍在尝试通过 phone 进行检查),还有其他需要验证的地方吗?

在致电 GlobalPay 后,他们坚持我应该尝试使用他们的 PHP SDK(最适合我的堆栈的选项)。事实上,我们现在正在使用它,这个检查版本的过程现在正在运行。

如果JSON有问题,那可能是授权问题。在授权中有一个方案:“securehash”和一个参数:sha1hashed 值。授权可以和其他的分开设置headers.

此示例代码在 C# 中使用 System.Net.Http:

    public static string SendJsonHttpClientRequest(string jsonobject, string url, string authorization)
    {
        var client = new HttpClient();
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("securehash", authorization);

        var request = new HttpRequestMessage
        {
            Method = HttpMethod.Post,
            RequestUri = new Uri(url),
            
            Headers =
            {
                {"X-GP-VERSION", "2.2.0" },


            },
            Content = new StringContent(jsonobject, Encoding.UTF8, "application/json")

        };
        

        var result = client.SendAsync(request).Result;
        var content = result.Content.ReadAsStringAsync().Result;

        return content;
    }

还值得检查您使用的帐户(sub-account)是否设置了 3dSecure 2,并且消息版本 2.1 和 2.2 有不同的测试卡