2015-01-14 2 views
7

Ho riscontrato un problema con la convalida di una ricevuta Apple sul lato server. Ho provato a trovare una soluzione in internet, ma non ci sono riuscito.Ricevimento acquisti in-app Apple - convalida sul lato server

Quindi, descrizione: Prima di tutto, l'applicazione è fatta per iOS7. In secondo luogo, ho alcuni elementi (tipo = abbonamento non rinnovabile). Quindi l'utente può acquistare uno o più oggetti e quindi dovrebbe rinnovarli manualmente (acquistare di nuovo).

Le applicazioni inviano una ricevuta al lato server, faccio una richiesta all'Apple e ottengo il risultato con un sacco di ricevute in_app. Qualcosa di simile:

"in_app":[ 
{ 
"quantity":"1", "product_id":"...", "transaction_id":"...", 
"original_transaction_id":"...", "purchase_date":"...", 
"purchase_date_ms":"...", "purchase_date_pst":"...", 
"original_purchase_date":"...", 
"original_purchase_date_ms":"...", "original_purchase_date_pst":"...", 
"is_trial_period":"..."}, 
{ 
"quantity":"1", "product_id":"...", 
"transaction_id":"...","original_transaction_id":"...", 
"purchase_date":"...", "purchase_date_ms":"...", 
"purchase_date_pst":"...", "original_purchase_date":"...", 
"original_purchase_date_ms":"...", "original_purchase_date_pst":"...", 
"is_trial_period":"..."} 
] 

Quindi, ogni "ricevuta" in "in_app" ha transaction_id. Ma come posso identificare il transactionId dell'acquisto corrente? Vorrei anche convalidarlo e assicurarmi che questo sia unico.

La mia preoccupazione è: se qualcuno riceverà una ricevuta valida, sarà in grado di hackerare la nostra API lato server e fare un numero illimitato di acquisti in-app con lo stesso scontrino valido.

Devo in qualche modo decodificare e controllare per transaction_id la ricevuta "originale", quella che invio ad Apple per la verifica?

Qualsiasi aiuto/suggerimento sarebbe molto apprezzato. Grazie in anticipo.

saluti, Maksim

+0

LOL ero solo chiedere lo stesso uomo domanda .. Ho trovato questo accidentalmente e ho visto che ti ha chiesto questo 8 ore fa ... questo solo sux, non ho la più pallida idea anche ciò che a che fare con tutte quelle ricevute ... – Adrian

+0

E voglio fare lo stesso tipo di controllo che volevi fare qui. Spero che qualcuno lo veda e lo risponda! : \ – Adrian

+3

Penso che la chiave sia ottenere l'ID della transazione dell'acquisto corrente sul lato * dell'app * e inviarlo, insieme alla ricevuta, fino al server. È possibile ottenere l'ID della transazione sul lato dell'app dall'oggetto transazione. –

risposta

0

@Doug Smith

https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html

Se si passa attraverso i diversi campi di questa pagina, troverete

identificatore di transazione originale :: Per una transazione che ripristina una transazione precedente, l'identificativo della transazione della transazione originale. Altrimenti, identico all'identificativo della transazione. Questo valore corrisponde alla proprietà transactionIdentifier della transazione originale. Tutte le entrate in una catena di rinnovi per un abbonamento auto-rinnovabile hanno lo stesso valore per questo campo.

Quindi per la vostra non-auto abbonamenti rinnovabili, è necessario tenere traccia delle due cose sul lato server:

  1. L'identificatore transazione originale della ricevuta che si stanno convalidando con server iTunes, socio questo con l'ID utente nel tuo database.
  2. Se la richiesta ricevuta dal lato client è di un acquisto o di un acquisto di ripristino.

Una volta che hai queste due cose con voi, è possibile scrivere la vostra logica su questi due parametri come di seguito:

:: Se la richiesta è di tipo "Acquista" e avete già l'identificatore di transazione originale di quella ricevuta associata ad un altro ID utente, è possibile bloccare tale acquisto.

:: Se una richiesta è di tipo "Ripristina acquisto" e la richiesta proviene dallo stesso ID utente rispetto al quale l'identificativo transazione originale è associato nel DB piuttosto che consentirgli altrimenti bloccare il ripristino.

Inoltre, è possibile derivare la propria logica basata su queste cose, in base alle proprie esigenze.

Fatemi sapere se avete ulteriori dubbi.

+0

Il mio problema è che la proprietà 'transaction_id' non si aggiorna mai da quella originale nella ricevuta JSON. –

+0

Ma si ricevono due due dizionari in JSON. Uno corrispondente alla transazione originale e altro per la transazione che hai appena eseguito. –

0

Per ogni nuova transazione, Apple invia una nuova ricevuta che è univoca, la codifica in modo che nessuno possa falsificare i dati.

Ottenere la ricevuta della transazione dalla transazione completata codificarlo e inviarlo al server, e sul lato server decodificarlo e corrispondere con l'invio di una mela al server.

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions 
{ 
    _transactionArray = transactions; 
    for (SKPaymentTransaction * transaction in transactions) 
    { 
     switch (transaction.transactionState) 
     { 
      case SKPaymentTransactionStatePurchased: { 
       NSData *receipt = transaction.transactionReceipt; 
       [self sendReceiptToServer]; 
      } break; 

      case SKPaymentTransactionStateFailed: { 
       // finish this transaction 
      } break; 

      case SKPaymentTransactionStateRestored: 
       NSData *receipt = transaction.transactionReceipt; 
       [self sendReceiptToServer:receipt]; 
      } break; 

      default: 
       break; 
     } 
    }; 
} 


-(void)sendReceiptToServer:(NSData *)receipt { 
    // encode receipt 
    // send receipt to server 
    // add success and error callback 
} 

-(void) receiptSuccess { 
    // finish transaction here 
} 

-(void) receiptError { 
    // try again sending receipt to server 
} 
+0

Pochi problemi con questo codice: 1) '- [SKPaymentTransaction transactionReceipt]' è deprecato da iOS7, invece '[[NSBundle mainBundle] appStoreReceiptURL]' dovrebbe essere usato. 2) Le transazioni devono essere completate indipendentemente dal loro stato di completamento, quindi '- [SKPaymentQueue finishTransaction:]' deve essere invocato in tutti i casi (ad eccezione del caso predefinito). –