2015-02-26 12 views
7

Sto lavorando a un'applicazione C# VS2012 Framework 4.5 MVC che sta tentando di diventare PCI compatibile con Payflow Pro (https://pilot-payflowpro.paypal.com). Usiamo PayflowPro da anni e questo è quello che devo usare. Dalla mia lettura sembra che dovrei usare il reindirizzamento trasparente, quindi non sto postando nulla di privato al mio server web, anche se non so se ne ho bisogno con quello che spero di gestire. Ho anche un paio di domande ...Paypal Payflow Reindirizzamento trasparente, SecureToken con AJAX?

come penso questo tutte le opere: mia comprensione è che avete bisogno di un securetoken (comunicazione a Paypal, viaggio 1). Quindi si inviano i dati protetti (CC, exp, codice di sicurezza) incluso il servizio di blocco (comunicazione a Paypal, viaggio 2) e ricevono l'autorizzazione e l'ID transazione della vendita.

Come spero di farlo: Ho intenzione di avere una forma che avrà tutte le informazioni (dati utente, dati di spedizione e informazioni CC), e quando l'utente preme il pulsante di acquisto , Userò AJAX per elaborare il viaggio 1 sul mio server (nessuna informazione utente sicura inviata). Qui creerò l'URL + params e invierò a paypal le mie informazioni un/pw per recuperare il token (tutto dal mio server). La risposta verrà restituita al client e, in caso di esito positivo, comunicherò direttamente tramite AJAX al server Gateway di Paypal, inviando questa volta il token info + token sicuro (viaggio n. 2). Sulla base della risposta al viaggio n. 2, farò sapere all'utente cosa succede con il loro acquisto. Il viaggio 2 non dovrebbe aver bisogno delle informazioni Paypal UN/PW in quanto potrebbe facilmente essere visualizzato sul client e sto includendo il SecureToken che DOVREBBE identificare la transazione originale. Da quello che ho spiegato non vedo la necessità di Transparent Redirect. O mi sto perdendo qualcosa qui?

Inoltre, quale tipo di transazione si desidera utilizzare? Crea una "Autorizzazione" per il viaggio n. 1, quindi una "Vendita" per il viaggio n. 2?

Quindi, ecco la Nitty Gritty roba tipo di codifica: Per il mio R & test D sto costruendo la mia stringa di parametri coppia nome/valore (vedi sotto) e comunicare al server gateway tramite WebRequest attraverso il loro sandbox/url di test (pilot-payflowpro.paypal.com). Ricevo una risposta di successo e SECURETOKENback. La richiesta iniziale (mostrata sotto) per token sicuro è TRXTYPE = A (Autorizzazione), nessuna informazione sulla carta viene inviata. Voglio prima autorizzare?

Qui sono i miei parametri (potrebbe includere informazioni ShipTo pure, ma non è elencato di seguito):

USER=myAuthUserName 
&VENDOR=myAuthUserName 
&PARTNER=myPartner 
&PWD=myPassword 
&AMT=21.43 
&BILLTOFIRSTNAME=FName 
&BILLTOLASTNAME=LName 
&BILLTOSTREET=123 Main Street 
&BILLTOSTREET2=Apt 203B 
&BILLTOCITY=MyCity 
&BILLTOSTATE=CA 
&BILLTOZIP=77777 
&BILLTOPHONENUM=4444444444 
&[email protected] 
&CURRENCY=USD 
**&TRXTYPE=A** 
&SILENTTRAN=TRUE 
&CREATESECURETOKEN=Y 
&SECURETOKENID=a99998afe2474b1b82c8214c0824df99 

Come ho detto, ho una risposta positiva e passare alla successiva fase di invio dei dati sicuro (CC#, EXPDATE, codice di sicurezza). Quando rimuovo le informazioni UN/PW/VENDOR/Partner dai parametri, viene visualizzato un errore a causa dell'autenticazione dell'utente non valida. Ma visto che sto costruendo dinamicamente questa seconda chiamata non posso avere il mio paypal un/pw lì. Cosa mi manca? Qualcuno offre assistenza con questa o altre domande dall'alto?

Per favore fatemi sapere se ho bisogno di qualche chiarimento da aggiungere. Grazie in anticipo per il tuo tempo!

+0

Guardando il documento che si trova qui: https: //developer.paypal.com/docs/classic/payflow/integration-guide/# about-the-secure-token "Il server gateway associa il proprio ID a un token sicuro e restituisce il token come una stringa composta da un massimo di 32 caratteri alfanumerici A passare i dati della transazione alla pagina di pagamento in hosting, si passa il token sicuro e l'ID del token protetto in un post di modulo HTTP: il token e l'ID attivano il server gateway per recuperare i dati e visualizzarli per l'approvazione del cliente. " Usiamo il nostro carrello della spesa in casa quindi non sto usando pagine HOSTED, forse questo è il mio problema? – RichieMN

+0

SEMBRA che utilizzando questo metodo sia necessario includere informazioni di autenticazione con ogni richiesta. Esaminando l'API REST di Paypal. Creerò un'altra domanda/commento con quello che imparo ... – RichieMN

+0

Hmmm. Ho solo provato a implementarlo e non funziona. Quando eseguo il reindirizzamento all'URL payflowlink, risponde con HTTP200 e nessun corpo HTML (e nessun reindirizzamento). Ho parlato con il supporto tecnico di PayPal e hanno detto che questa sequenza non è possibile: il modulo di input della carta di credito deve essere ospitato sul server paypal per utilizzare payflowlink (utilizzando un iFrame per incorporarlo sul nostro sito). Sono stato indirizzato all'API DoDirectPayment. Ci vorrà del tempo per fare un test. – Owen

risposta

3

Sono stato in grado di utilizzare la risposta di RichieMN per ottenere il funzionamento di Redirect trasparente. Tuttavia, il problema con il reindirizzamento con window.location.replace nella funzione SendCCDetailsToPaypal consiste nel passare i dati su una stringa GET.

questo funziona sul lato PayFlow Gateway, ma quando inviano il browser del cliente di nuovo al vostro responseURL, i log di Apache mostrerà l'intero URL payflowlink.paypal.com , tra cui la stringa GET come il referrer nella vostra Apache log di accesso! Quella stringa GET include il numero della carta di credito e ora hai perso la tua conformità PCI!

per alleviare questo problema, è possibile mettere il SecureToken e SecureTokenID nel vostro modulo di iscrizione con carta di credito, e post-it direttamente a payflowlink.paypal.com, oppure si può riscrivere il SendCCDetailsToPaypal funzione di costruire un modulo e inviarlo che, in questo modo:

function SendCCDetailsToPaypal() { 
    var parameters = { 
     "SECURETOKEN": secureToken, 
     "SECURETOKENID": secureTokenID, 
     "ACCT": $("#ccNumber").val(), 
     "EXPDATE": $("#expMonth").val() + $("#expYear").val(), 
     "CSC": $("#ccSecurityCode").val() 
    }; 
    var form = $('<form></form>'); 
    form.attr("method", "post"); 
    form.attr("action", "https://pilot-payflowlink.paypal.com"); 
    $.each(parameters, function(key, value) { 
     var field = $('<input></input>'); 
     field.attr("type", "hidden"); 
     field.attr("name", key); 
     field.attr("value", value); 
     form.append(field); 
    }); 
    $(document.body).append(form); 
    form.submit(); 
} 

Da quel modulo trasferisce i dati tramite POST, quando il server ottiene il risultato di nuovo POST, il referrer non contiene dati sensibili, e la conformità PCI è mantenuta.

+0

Bella cattura, grazie! – RichieMN

6

Dopo aver trascorso un po 'di tempo con un ingegnere Paypal, ho trovato una soluzione per il reindirizzamento trasparente Payflow di Paypal senza pagine ospitate (possedere una pagina di pagamento). Di nuovo, ecco la documentazione che, secondo l'ingegnere, è piuttosto confusa: Payflow API Documentation. Inoltre, il codice non è ottimizzato perché era solo un'app R & D, ma nel complesso funziona per me. Solo un esempio e una spiegazione, e sono sicuro che ci sono modi migliori per fare passi individuali. Spero che questo ti aiuti e ti permetta di aggirare alcuni dei blocchi stradali che hanno rallentato la tua integrazione con Paypal Payflow.

Sì, è conforme PCI in quanto nessun dato di cliente sicuro colpirà i vostri server. Ricorda che la conformità PCI è piuttosto complicata e coinvolta, ma questa è una parte importante. Ok, quindi spiegherò cosa ho fatto per farlo funzionare in un ambiente MVC C#. Spiegherò i passaggi qui, quindi includerò il codice qui sotto.

  1. CLIENTE: il cliente termina l'aggiunta di articoli al carrello e preme il pulsante ACQUISTA. Javascript gestisce il clic del pulsante, non invia e ti porta al passaggio successivo.
  2. CLIENT -> SERVER: funzione AJAX POSTA al metodo server per contattare Paypal per il token sicuro monouso. Questa comunicazione identifica VOI (il commerciante) a paypal con la vostra autenticazione, un ID transazione univoco (un guid) e dettagli non sicuri sulla transazione (totale, informazioni di fatturazione, informazioni sulla spedizione, dettagli dell'URL di ritorno). In questo modo, tutte le informazioni sull'accesso personale del commerciante sono sicure (server web su Paypal).
  3. SERVER -> CLIENT: dalla transazione precedente riceverai una stringa di parametri che contiene il token sicuro (tra le altre cose, vedi il metodo con l'esempio). Usando questa informazione, creo dinamicamente il mio url che alla fine avrò bisogno del client per la parte di reindirizzamento trasparente e invierò la stringa url al client.
  4. CLIENT: Utilizzando l'url restituito nel passaggio n. 3, ho completato l'URL aggiungendo i parametri della carta di credito necessari utilizzando jQuery.
  5. CLIENTE -> PAYPAL: è qui che non ho capito cosa fare. Mentre il passaggio n. 2 era un post, questo passaggio sarà un REDIRECT. Certo, sembra appropriato vederlo chiamato 'reindirizzamento trasparente', ma quella parte non aveva senso per me. Quindi, una volta completato l'intero URL, dovrai letteralmente reindirizzare la finestra a Paypal per elaborare la tua transazione.
  6. PAYPAL -> SERVER: PayPal invia di nuovo uno degli URL inclusi nel passaggio 2 (a un metodo pubblico su uno dei miei controller), e leggo l'oggetto risposta e analizzo i parametri.

Facile, giusto? Forse, ma per me il punto 5 mi ha causato grossi problemi. Stavo usando un POST e non ho capito perché continuavo a ricevere errori nella risposta. Era una pagina html con qualcosa su un commerciante o un'autenticazione non valida. Ricordati di reindirizzare, non pubblicare per il passaggio n.

CODICE:

FASE 1: onclick attributo sul pulsante per chiamare la funzione GetToken.

passaggi 2 e 3:

lato client:

function GetToken() { 
$.ajax({ 
    url: '@Url.Action("GetToken", "MyController")', 
    type: 'POST', 
    cache: 'false', 
    contentType: 'application/json; charset=utf-8', 
    dataType: 'text', 
    success: function (data) { 
     // data is already formatted in parameter string 
     SendCCDetailsToPaypal(data); 
    }, 
    //error: 
    //TODO Handle the BAD stuff 
});} 

Server Side:

ho metodi separati utilizzati per costruire tutti i valori dei parametri necessari per la richiesta di token. Prime tre build: autenticazione, dettagli della transazione, reindirizzamento trasparente. Conservo gli URL e le informazioni sull'accesso ai flussi di pagamento in un file web.config. L'ultimo metodo, ProcessTokenTransaction, fa tutto il lavoro necessario per contattare Paypal tramite WebRequest e quindi analizzarlo nell'URL che verrà inviato al client. Questo metodo dovrebbe essere refactored per una consegna più pulita, ma lascerò a voi. ParseResponse è un metodo che popola un modello semplice che ho creato e restituisce quel modello.

URL del token (sandbox):https://pilot-payflowpro.paypal.com

Questo è diverso l'URL TOKEN !! Utilizzato nel valore di configurazione PaypalTranactionAPI.

URL per la transazione: (sandbox)https://pilot-payflowlink.paypal.com

private string PrepareApiAuthenticationParams()   
    { 
     var paypalUser = ConfigurationManager.AppSettings["PaypalUser"]; 
     var paypalVendor = ConfigurationManager.AppSettings["PaypalVendor"]; 
     var paypalPartner = ConfigurationManager.AppSettings["PaypalPartner"]; 
     var paypalPw = ConfigurationManager.AppSettings["PaypalPwd"]; 

     //var amount = (decimal)19.53; 

     var apiParams = @"USER=" + paypalUser 
         + "&VENDOR=" + paypalVendor 
         + "&PARTNER=" + paypalPartner 
         + "&PWD=" + paypalPw 
         + "&TENDER=C" 
         + "&TRXTYPE=A" 
         + "&VERBOSITY=HIGH"; 

     // find more appropriate place for this param 
     //+ "&VERBOSITY=HIGH"; 

     return apiParams; 
    } 


    private string PrepareTransactionParams(CustomerDetail detail) 
    { 
     var currencyType = "USD"; 

     var transactionParams = @"&BILLTOFIRSTNAME=" + detail.FirstName 
           + "&BILLTOLASTNAME=" + detail.LastName 
           + "&BILLTOSTREET=" + detail.Address1 
           + "&BILLTOSTREET2=" + detail.Address2 
           + "&BILLTOCITY=" + detail.City 
           + "&BILLTOSTATE=" + detail.State 
      //+ "&BILLTOCOUNTRY=" + detail.Country + // NEEDS 3 digit country code 
           + "&BILLTOZIP=" + detail.Zip 
           + "&BILLTOPHONENUM=" + detail.PhoneNum 
           + "&EMAIL=" + detail.Email 
           + "&CURRENCY=" + currencyType 
           + "&AMT=" + GET_VALUE_FROM_DB 
           + "&ERRORURL= " + HostUrl + "/Checkout/Error" 
           + "&CANCELURL=" + HostUrl + "/Checkout/Cancel" 
           + "&RETURNURL=" + HostUrl + "/Checkout/Success"; 

     // ADD SHIPTO info for address validation 

     return transactionParams; 
    } 


private string PrepareTransparentParams(string requestId, string transType) 
    { 
     var transparentParams = @"&TRXTYPE=" + transType + 
           "&SILENTTRAN=TRUE" + 
           "&CREATESECURETOKEN=Y" + 
           "&SECURETOKENID=" + requestId; 

     return transparentParams; 
    } 


    // Method to build parameter string, and create webrequest object 
public string ProcessTokenTransaction() 
    { 
     var result = "RESULT=0"; // default failure response 
     var transactionType = "A"; 
     var secureToken = string.Empty; 
     var requestId = Guid.NewGuid().ToString().Replace("-", string.Empty); 

     var baseUrl = ConfigurationManager.AppSettings["PaypalGatewayAPI"];    

     var apiAuthenticationParams = PrepareApiAuthenticationParams(); 

     // Create url parameter name/value parameter string 
     var apiTransactionParams = PrepareTransactionParams(detail); 

     // PCI compliance, Create url parameter name/value parameter string specific to TRANSAPARENT PROCESSING 
     var transparentParams = PrepareTransparentParams(requestId, transactionType); 

     var url = baseUrl; 
     var parameters = apiAuthenticationParams + apiTransactionParams + transparentParams; 


     // base api url + required 
     var request = (HttpWebRequest)WebRequest.Create(url); 
     request.Method = "POST"; 
     request.ContentType = "text/name"; // Payflow? 
     request.Headers.Add("X-VPS-REQUEST-ID", requestId); 

     byte[] bytes = Encoding.UTF8.GetBytes(parameters); 
     request.ContentLength = bytes.Length; 

     Stream requestStream = request.GetRequestStream(); 
     requestStream.Write(bytes, 0, bytes.Length); 
     requestStream.Close(); 


     WebResponse response = request.GetResponse(); 
     Stream stream = response.GetResponseStream(); 
     StreamReader reader = new StreamReader(stream); 

     try 
     { 

      // sample successful response 
      // RESULT=0&RESPMSG=Approved&SECURETOKEN=9pOyyUMAwRUWmmv9nMn7zhQ0h&SECURETOKENID=5e3c50a4c3d54ef8b412e358d24c8915 

      result = reader.ReadToEnd(); 

      var token = ParseResponse(result, requestId, transactionType); 

      var transactionUrl = ConfigurationManager.AppSettings["PaypalTransactionAPI"]; 
      secureToken = transactionUrl + "?SECURETOKEN=" + token.SecureToken + "&SECURETOKENID=" + requestId; 

      //ameValueCollection parsedParams = HttpUtility.ParseQueryString(result);     

      stream.Dispose(); 
      reader.Dispose(); 
     } 
     catch (WebException ex) 
     { 
      System.Diagnostics.Trace.WriteLine(ex.Message); 

     } 
     finally { request.Abort(); } 

     return secureToken; 
    } 


private TokenResponse ParseResponse(string response, string requestId, string transactionType) 
    { 
     var nameValues = HttpUtility.ParseQueryString(response); 

     int result = -999; // invalid result to guarantee failure 

     int.TryParse(nameValues.Get(TokenResponse.ResponseParameters.RESULT.ToString()), out result); 

     // retrieving response message 
     var responseMessage = nameValues.Get(TokenResponse.ResponseParameters.RESPMSG.ToString()); 

     // retrieving token value, if any 
     var secureToken = nameValues.Get(TokenResponse.ResponseParameters.SECURETOKEN.ToString()); 

     var reference = nameValues.Get(TokenResponse.ResponseParameters.PNREF.ToString()); 

     var authCode = nameValues.Get(TokenResponse.ResponseParameters.AUTHCODE.ToString()); 

     var cscMatch = nameValues.Get(TokenResponse.ResponseParameters.CSCMATCH.ToString()); 

     // populating model with values 
     var tokenResponse = new TokenResponse 
     { 
      Result = result, 
      ResponseMessage = responseMessage, 
      SecureToken = secureToken, 
      TransactionIdentifierToken = requestId, 
      TransactionType = transactionType, 
      ReferenceCode = reference, 
      AuthorizationCode = authCode, 
      CSCMatch = cscMatch 
     }; 

     return tokenResponse; 
    } 

FASE 4 e STEP 5:

Torna al lato client:

Qui uso l'URL integrato dai passaggi precedenti e aggiungi i parametri necessari finali (informazioni sicure sulla carta di credito) usando jQuery e poi REDIRECT t o Paypal.

function SendCCDetailsToPaypal(secureParm) { 

    //alert('in SendCCDetailsToPaypal:' + secureParm); 

    var secureInfo = '&ACCT=' + $('#ccNumber').val() + '&EXPDATE=' + $("#expMonth").val() + $("#expYear").val() + "&CSC=" + $('#ccSecurityCode').val(); 
    secureInfo = secureParm + secureInfo; 

    window.location.replace(secureInfo);    
} 

FASE 6:

Paypal invierà di nuovo ad uno dei seguenti metodi: Cancellare, errore, o Return (un nome al metodo tutto quello che vuoi nella richiesta token). Analizza la risposta e osserva le variabili restituite da Paypal, in particolare RISULTATO e RESPMSG. Leggi la documentazione per le specifiche in quanto puoi incorporare la convalida degli indirizzi e molte altre funzionalità. In base alla risposta, visualizza ciò che è appropriato. lato

server:

public ActionResult Cancel() 
    { 
     var result = ParseRequest(HttpUtility.UrlDecode(Request.Params.ToString())); 

     //return View("Return", result); 
    } 


    public ActionResult Error() 
    { 

     var result = ParseRequest(HttpUtility.UrlDecode(Request.Params.ToString())); 

     return View("Return", result); 
    } 


    public ActionResult Return() 
    { 
     var result = ParseRequest(HttpUtility.UrlDecode(Request.Params.ToString())); 

     return View("Return", result); 
    } 

Spero che questo aiuti, e buona fortuna! Risponderò alle domande di chiarimento come sono in grado. Grazie per averlo verificato e ricordati di ripagarlo.

+1

hai effettuato una convalida nell'URL di ritorno prima di continuare il pagamento? come la convalida che si tratta di una transazione reale e qualcuno non ha appena creato un URL di ritorno. – Justin

+1

Grazie per la soluzione. Questo funziona per me, ma ho dovuto impostare 'abilita token sicuro' su true nell'account amministratore affinché funzioni. Dovevi farlo anche tu? – mridula

Problemi correlati