Validating Receipts With the App Store

来源:https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW1

Note: There is a vulnerability in iOS 5.1 and earlier related to receipt validation with the app store directly from a device, without using a server. For more details and a mitigation strategy, see In-App Purchase Receipt Validation on iOS.

Use a trusted server to communicate with the App Store. Using your own server lets you design your app to recognize and trust only your server, and lets you ensure that your server connects with the App Store server. It is not possible to build a trusted connection between a user’s device and the App Store directly because you don’t control either end of that connection.

Communication with the App Store is structured as JSON dictionaries, as defined in RFC 4627. Binary data is base64 encoded, as defined in RFC 4648.

Read the Receipt Data

To retrieve the receipt data, use the appStoreReceiptURL method of NSBundle to locate the app’s receipt, and then read the entire file. If the appStoreReceiptURL method is not available, you can fall back to the value of a transaction's transactionReceipt property for backward compatibility. Then send this data to your server—as with all interactions with your server, the details are your responsibility.

// Load the receipt from the app bundle.
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
if (!receipt) { /* No local receipt -- handle the error. */ }
 
/* ... Send the receipt data to your server ... */

Send the Receipt Data to the App Store

On your server, create a JSON object with the following keys:

Key
Value

receipt-data

The base64 encoded receipt data.

password

Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string).

Submit this JSON object as the payload of an HTTP POST request. In the test environment, use https://sandbox.itunes.apple.com/verifyReceipt as the URL. In production, usehttps://buy.itunes.apple.com/verifyReceipt as the URL.

NSData *receipt; // Sent to the server by the device
 
// Create the JSON object that describes the request
NSError *error;
NSDictionary *requestContents = @{
    @"receipt-data": [receipt base64EncodedStringWithOptions:0]
};
NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
                                                      options:0
                                                        error:&error];
 
if (!requestData) { /* ... Handle error ... */ }
 
// Create a POST request with the receipt data.
NSURL *storeURL = [NSURL URLWithString:@"https://buy.itunes.apple.com/verifyReceipt"];
NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
[storeRequest setHTTPMethod:@"POST"];
[storeRequest setHTTPBody:requestData];
 
// Make a connection to the iTunes Store on a background queue.
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
        completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    if (connectionError) {
        /* ... Handle error ... */
    } else {
        NSError *error;
        NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
        if (!jsonResponse) { /* ... Handle error ...*/ }
        /* ... Send a response back to the device ... */
    }
}];

Parse the Response

The response’s payload is a JSON object that contains the following keys and values:

Key
Value

status

Either 0 if the receipt is valid, or one of the error codes listed in Table 2-1.

For iOS 6 style transaction receipts, the status code reflects the status of the specific transaction’s receipt.

For iOS 7 style app receipts, the status code is reflects the status of the app receipt as a whole. For example, if you send a valid app receipt that contains an expired subscription, the response is 0 because the receipt as a whole is valid.

receipt

A JSON representation of the receipt that was sent for verification. For information about keys found in a receipt, see Receipt Fields.

latest_receipt

Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions. The base-64 encoded transaction receipt for the most recent renewal.

latest_receipt_info

Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions. The JSON representation of the receipt for the most recent renewal.

Table 2-1  Status codes

Status Code

Description

21000

The App Store could not read the JSON object you provided.

21002

The data in the receipt-data property was malformed or missing.

21003

The receipt could not be authenticated.

21004

The shared secret you provided does not match the shared secret on file for your account.

Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions.

21005

The receipt server is not currently available.

21006

This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.

Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions.

21007

This receipt is from the test environment, but it was sent to the production environment for verification. Send it to the test environment instead.

21008

This receipt is from the production environment, but it was sent to the test environment for verification. Send it to the production environment instead.

The values of the latest_receipt and latest_receipt_info keys are useful when checking whether an auto-renewable subscription is currently active. By providing any transaction receipt for the subscription and checking these values, you can get information about the currently-active subscription period. If the receipt being validated is for the latest renewal, the value for latest_receipt is the same as receipt-data (in the request) and the value for latest_receipt_info is the same as receipt.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Shiro中,当会话过期或无效时,可能会出现“Error while validating the session java.lang.NullPointerException: null”的错误。这通常是由于在会话过期或无效时尝试访问会话属性而导致的。为了解决这个问题,您可以在Shiro配置文件中配置一个错误页面,以便在会话过期或无效时重定向到该页面。以下是一个示例配置: ```xml <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- ... other properties ... --> <property name="filters"> <util:map> <entry key="authc"> <bean class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"> <property name="loginUrl" value="/login"/> <property name="errorUrl" value="/login?error=true"/> </bean> </entry> </util:map> </property> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/login"/> <property name="successUrl" value="/"/> <property name="unauthorizedUrl" value="/403"/> <property name="filterChainDefinitions"> <value> /login = authc /** = anon </value> </property> <property name="errorPages"> <util:map> <entry key="org.apache.shiro.authz.UnauthorizedException" value="/403"/> <entry key="org.apache.shiro.authc.AuthenticationException" value="/login?error=true"/> <entry key="java.lang.Exception" value="/error"/> </util:map> </property> </bean> ``` 在这个示例中,我们配置了一个错误页面映射,以便在会话过期或无效时重定向到“/login?error=true”页面。这将确保用户在会话过期或无效时不会看到“Error while validating the session java.lang.NullPointerException: null”的错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值