Implementation of Apple In-App Payment Server

This article mainly talks about the server-side implementation steps for mobile APP to realize Apple payment.

 

For the process of Apple in-app payment, please refer to:

1. Official website description: https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW1

 

2. Chinese blog: https://mengkang.net/723.html

 

A brief description is as follows:

1. First, the client first requests the Apple payment center, and the payment center returns a bunch of encrypted data to the client.

2. The client then transmits the encrypted data to the server.

3. Finally, the server will request the Apple Payment Center to verify whether the purchase is successful. If the verification is passed, the server side processes the business logic.

 

The implementation of this example:

The communication method of websocket + JSON format data used between the client and the server.

The business logic part of the server is written in Perl language.

 

1. Interface parameters

{

"order_id" : order number (generated by the front-end, within 32 characters, to ensure uniqueness)

"receipt_data" : "MIITuwYJKoZIhvcNAQcCoIITrDCCE6g..." The encrypted data returned by the payment center to the client

}

 

2. The server requests the payment center to verify the ticket

sub apple_check_receipt {

    my $receipt_data = $_[0];

 

    my $endpoint_debug = "https://sandbox.itunes.apple.com/verifyReceipt"; #Development environment, using apple sandbox address

    if(__PACKAGE__ eq "PRODUCT") {

        $endpoint_debug = "https://buy.itunes.apple.com/verifyReceipt"; #生产环境

    }

    # 构造请求的参数(json格式)

    my $apple_receipt;

    $apple_receipt->{"receipt-data"} = $receipt_data;

 

    my $header = HTTP::Headers->new( Content_Type => 'application/json; charset=utf8', );

    my $json = JSON->new();

    my $http_request = HTTP::Request->new( POST => $endpoint_debug, $header, $json->encode($apple_receipt));

 

    #anlyse this response

    my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0x00 });

    $ua->timeout(30); 

    my $response = $ua->request($http_request);

    my $json_return;

    if ($response->message ne "OK" && $response->is_success ne "1") { #出错,或者timeout了

        return "timeout";

    } else {

        $json_return =  $json->decode($response->content());

    }

    # 验证苹果中心返回的结果

    if ($json_return->{status} eq "0") {

        my $in_app = $json_return->{receipt}->{in_app}[0];

        $result->{transaction_id} = $in_app->{transaction_id};

        if (length($result->{transaction_id}) == 0) {

            return "transaction_id is null";

        } elsif (length($in_app->{product_id}) == 0 || index($in_app->{product_id}, "abc.cdf.x") < 0) {

            return "product_id is invalid";

        }

         # 根据业务需求,验证其他字段

        .....

    }

    return "success";

}

 

验证票据请求返回结果的内容一般如下:

response: {

       environment: "Production", 

        receipt: {

            adam_id: 1155833660, 

            app_item_id: 1155833660, 

            application_version: "1", 

            bundle_id: "**********", 

            download_id: null, 

            in_app: [

                {

                    is_trial_period: "false", 

                    original_purchase_date: "2017-02-21 06:25:12 Etc/GMT", 

                    original_purchase_date_ms: "1487658312000", 

                    original_purchase_date_pst: "2017-02-20 22:25:12 America/Los_Angeles", 

                    original_transaction_id: "710000191974963", 

                    product_id: "***********", 

                    purchase_date: "2017-02-21 06:25:12 Etc/GMT", 

                    purchase_date_ms: "1487658312000", 

                    purchase_date_pst: "2017-02-20 22:25:12 America/Los_Angeles", 

                    quantity: "1", 

                    transaction_id: "710000191974963"

                }

            ], 

            original_application_version: "1", 

            original_purchase_date: "2017-02-21 06:25:12 Etc/GMT", 

            original_purchase_date_ms: "1487658312000", 

            original_purchase_date_pst: "2017-02-20 22:25:12 America/Los_Angeles", 

            receipt_creation_date: "2017-02-21 06:25:12 Etc/GMT", 

            receipt_creation_date_ms: "1487658312000", 

            receipt_creation_date_pst: "2017-02-20 22:25:12 America/Los_Angeles", 

            receipt_type: "Production", 

            request_date: "2017-02-21 06:25:22 Etc/GMT", 

            request_date_ms: "1487658312010", 

            request_date_pst: "2017-02-20 22:25:22 America/Los_Angeles", 

            version_external_identifier: 820590861

        }, 

        status: "0"

 

    },

每个字段的含义可以参考官网说明:https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1

 

关键信息是在 in_app这个数组里面,可以根据自身情况,校验相应字段的合法性。

 

生产环境中还经常出现in_app为空数组的情况,比如下面的结果:

response: {

        environment: "Production", 

        receipt: {

            adam_id: 1155833660, 

            app_item_id: 1155833660, 

            application_version: "1", 

            bundle_id: "***********", 

            download_id: 83024344988508, 

            in_app: [ ], 

            original_application_version: "1", 

            original_purchase_date: "2017-03-26 10:26:17 Etc/GMT", 

            original_purchase_date_ms: "1490523977000", 

            original_purchase_date_pst: "2017-03-26 03:26:17 America/Los_Angeles", 

            receipt_creation_date: "2017-03-26 10:26:17 Etc/GMT", 

            receipt_creation_date_ms: "1490523977000", 

            receipt_creation_date_pst: "2017-03-26 03:26:17 America/Los_Angeles", 

            receipt_type: "Production", 

            request_date: "2017-03-26 10:26:27 Etc/GMT", 

            request_date_ms: "1490523977010", 

            request_date_pst: "2017-03-26 03:26:27 America/Los_Angeles", 

            version_external_identifier: 821061739

        }, 

        status: "0"

    },

 

这种都是不正常的。

 

另外客户端输入参数里面有order_id(保证唯一性)可以用来防止同一个票据数据receipt_data,重复发送导致服务端重复执行业务逻辑的问题。

 

 

 

 

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326122645&siteId=291194637