2015-02-26 11 views
7

Ich arbeite an einer C# VS2012 Framework 4.5 MVC-Anwendung, die versucht, PCI-kompatibel mit Payflow Pro (https://pilot-payflowpro.paypal.com) zu werden. Wir verwenden PayflowPro seit Jahren, und das ist es, was ich verwenden muss. Aus meiner Lektüre scheint es, dass ich die Transparent Redirect verwenden sollte, so dass ich nichts Privates auf meinem Webserver posten werde, obwohl ich nicht weiß, ob ich das brauche, mit dem, was ich mir erhoffe. Ich habe auch ein paar Fragen ...Paypal Payflow Transparente Umleitung, SecureToken mit AJAX?

Wie ich denke, das alles funktioniert: Mein Verständnis ist, dass Sie einen Securetoken (Kommunikation zu Paypal, Reise 1) benötigen. Dann posten Sie die gesicherten Daten (CC, exp, Sicherheitscode) inklusive des securetoken (Kommunikation zu Paypal, trip 2) und erhalten die Autorisierung und Transaktions-ID des Verkaufs.

Wie ich hoffe, es zu tun: ich mit einer Form bin die Absicht, die alle Informationen (Benutzerdaten, Versanddetails und CC info), und wenn der Benutzer auf den Kaufknopf hat Ich verwende AJAX, um Trip 1 zu meinem Server zu verarbeiten (keine gesicherten Benutzerinformationen gesendet). Hier erstelle ich die URL + params und sende paypal meine un/pw info, um das Token (alles von meinem Server) zu erhalten. Die Antwort wird an den Client zurückgegeben, und wenn dies erfolgreich ist, werde ich direkt über AJAX mit dem Gateway-Server von Paypal kommunizieren und diesmal das sichere CC info + -Token senden (Trip # 2). Basierend auf der Antwort auf Trip # 2, werde ich den Benutzer wissen lassen, was mit dem Kauf passiert ist. Reise 2 sollte nicht meine Paypal UN/PW Informationen benötigen, da es leicht auf dem Client zu sehen ist, und ich schließe das SecureToken ein, das die ursprüngliche Transaktion identifizieren sollte. Nach dem, was ich erklärt habe, sehe ich keinen Bedarf für Transparent Redirect. Oder verpasse ich hier etwas?

Welche Transaktionsart möchte ich auch verwenden? Erstellen Sie eine 'Autorisierung' für die Reise # 1 und dann eine 'Reise' für die Reise # 2?

hier ist also die Nitty Gritty Kodiertypänderung Sachen: Für meine R & D Test ich meinen eigenen Namen/Wert-Paar Parameterstring Aufbau (siehe unten) und über WebRequest durch ihre Sandbox zu dem Gateway-Server Kommunikation/Test-URL (pilot-payflowpro.paypal.com). Ich bekomme eine erfolgreiche Antwort und SECURETOKEN zurück. Die erste Anforderung (siehe unten) für das sichere Token lautet TRXTYPE = A (Autorisierung), es werden keine Karteninformationen gesendet. Möchte ich zuerst autorisieren?

Hier sind meine Parameter (könnte auch ShipTo Informationen umfassen, aber es ist nicht unten aufgeführt):

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 

Wie gesagt, ich eine erfolgreiche Antwort erhalten und zum nächsten Schritt bewegen, um die sicheren Daten zu senden (CC#, EXPDATE, Sicherheitscode). Wenn ich meine UN/PW/VENDOR/Partner-Informationen aus den Parametern lösche, erhalte ich einen Fehler aufgrund einer ungültigen Benutzerauthentifizierung. Aber da ich sehe, dass ich diesen 2. Aufruf dynamisch aufbaue, kann ich meine Paypal nicht dort haben. Was vermisse ich? Bietet jemand Hilfe bei dieser oder den anderen Fragen von oben an?

Bitte lassen Sie mich wissen, wenn ich eine Klarstellung hinzugefügt werden muss. Vielen Dank im Voraus für Ihre Zeit!

+0

Blick auf das Dokument befindet sich hier: https: //developer.paypal.com/docs/classic/payflow/integration-guide/# about-the-secure-token "Der Gateway-Server verknüpft Ihre ID mit einem sicheren Token und gibt das Token als Zeichenfolge mit bis zu 32 alphanumerischen Zeichen zurück. To Übergeben Sie die Transaktionsdaten an die gehostete Checkout-Seite, übergeben Sie das sichere Token und die sichere Token-ID in einem HTTP-Formularpost. Das Token und die ID lösen den Gateway-Server aus, um Ihre Daten abzurufen und zur Kundengenehmigung anzuzeigen. Wir verwenden unseren eigenen Einkaufswagen, so dass ich keine HOSTED-Seiten verwende, vielleicht ist das mein Problem? – RichieMN

+0

SCHEINT, dass Sie bei dieser Methode Authentifizierungsinformationen bei jeder Anfrage angeben müssen. Ein Blick in Paypals REST-API. Ich werde eine andere Frage/Kommentar mit was Iearn erstellen ... – RichieMN

+0

Hmmm. Ich habe gerade versucht, dies zu implementieren und es funktioniert nicht. Wenn ich die Umleitung zur Payflowlink-URL durchführe, antwortet sie mit HTTP200 und ohne HTML-Body (und ohne Redirect). Ich habe mit dem technischen Support von PayPal gesprochen und sie sagen, dass diese Reihenfolge nicht möglich ist: Das Kreditkarten-Eingabeformular muss auf dem Paypal-Server gehostet werden, um Payflowlink zu verwenden (mit einem iFrame, um es auf unserer Website einzubetten). Ich wurde zur DoDirectPayment API weitergeleitet. Wird einige Zeit brauchen, um einen Test zu erstellen. – Owen

Antwort

3

Ich konnte die Antwort von RichieMN verwenden, um ein funktionierendes transparentes Redirect zu erhalten. Das Problem mit einer Umleitung mit window.location.replace in der SendCCDetailsToPaypal Funktion ist jedoch, dass Sie die Daten für eine GET-Zeichenfolge übergeben.

Dies funktioniert auf der PayFlow Gateway-Seite, aber wenn sie den Browser des Kunden zurück zu Ihrem responseURL, Apache-Logs zeigen die ganze payflowlink.paypal.com URL, einschließlich dem GET-String als Referrer in Ihrem Apache senden Zugangsprotokolle! Dieser GET-String enthält die Kreditkartennummer und Sie haben gerade Ihre PCI-Compliance verloren!

dieses Problem zu lindern, können Sie entweder die Securetoken und SecureTokenID in Ihr Kreditkarteneingabeformular setzen, und per Post direkt an payflowlink.paypal.com, oder Sie können den SendCCDetailsToPaypal Funktion umschreiben, ein Formular zu erstellen und einreichen es, wie folgt aus:

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 diese Form die Daten per POST überträgt, wenn der Server wieder das Ergebnis POST wird, wird der Referrer enthält keine sensiblen Daten und Ihre PCI-Compliance eingehalten wird.

+0

Schöner Fang, danke! – RichieMN

6

Nachdem ich einige Zeit mit einem Paypal-Techniker verbracht habe, habe ich eine Lösung für Paypals Payflow Transparent Redirect ohne gehostete Seiten gefunden (eigene Zahlungsseite). Noch einmal, hier ist die Dokumentation, die für den Ingenieur ziemlich verwirrend ist: Payflow API Documentation. Außerdem ist der Code nicht optimiert, da es nur eine R & D App war, aber als Ganzes funktioniert es für mich. Nur ein Beispiel und eine Erklärung, und ich bin mir sicher, dass es bessere Möglichkeiten gibt, einzelne Schritte zu machen. Ich hoffe, dies hilft und ermöglicht es Ihnen, einige der Hindernisse zu umgehen, die Ihre Paypal Payflow-Integration verlangsamt haben.

JA, es ist PCI-konform, da keine sicheren Kundendaten Ihre eigenen Server treffen. Denken Sie daran, dass die PCI-Compliance ziemlich kompliziert und kompliziert ist, aber das ist ein großer Teil davon. Ok, ich werde erklären, was ich getan habe, um dies in einer MVC C# Umgebung zu ermöglichen. Ich werde die Schritte hier erklären und dann den Code unten einfügen.

  1. CLIENT: Der Client beendet das Hinzufügen von Artikeln zum Einkaufswagen und drückt die Taste KAUFEN. Javascript handhabt den Knopfklick, reicht nicht ein und bringt Sie zum nächsten Schritt.
  2. CLIENT -> SERVER: AJAX-Funktion POSTS zu Server-Methode, um Paypal für den Single-Use-Secure-Token zu kontaktieren. Diese Kommunikation identifiziert SIE (den Händler) mit Ihrer Authentifizierung, einer eindeutigen Transaktions-ID (einer GUID) und nicht sicheren Details über die Transaktion (Summe, Rechnungsinformationen, Versandinformationen, Rücksende-URL-Details). Auf diese Weise sind alle Ihre persönlichen Händleraccount Informationen sicher (Webserver zu Paypal).
  3. SERVER -> CLIENT: Von der Transaktion oben erhalten Sie eine Parameter-Zeichenfolge, die das sichere Token enthält (unter anderem, siehe Methode mit Beispiel). Mit diesem Teil der Informationen, ich dynamisch erstellen meine URL, die ich schließlich auf dem Client für die transparente Umleitung Teil benötigen, und senden Sie die URL-Zeichenfolge zurück an den Client.
  4. CLIENT: Unter Verwendung der URL, die in Schritt # 3 zurückgegeben wurde, vervollständige ich die URL, indem ich die benötigten Kreditkartenparameter mit jQuery hinzufüge.
  5. KUNDE -> PAYPAL: Hier habe ich nicht verstanden, was zu tun ist. Während Schritt 2 ein Post war, wird dieser Schritt ein REDIRECT sein. Sicher, das erscheint angemessen, da es "transparente Umleitung" genannt wird, aber dieser Teil ergab für mich keinen Sinn. Sobald Ihre gesamte URL vollständig ist, leiten Sie das Fenster zur Verarbeitung Ihrer Transaktion buchstäblich an Paypal um.
  6. PAYPAL -> SERVER: PayPal sendet zurück an eine der URLs, die Sie in Schritt 2 einbezogen haben (an eine öffentliche Methode auf einem meiner Controller), und ich lese das Antwortobjekt und parse die Parameter.

Einfach, oder? Vielleicht, aber für mich hat Schritt 5 große Probleme verursacht. Ich benutzte einen POST und konnte nicht verstehen, warum ich immer Fehler bei der Antwort bekam. Es war eine HTML-Seite mit etwas über einen ungültigen Händler oder eine Authentifizierung. Denken Sie daran, umzuleiten, nicht für Schritt # 5 zu posten.

CODE:

SCHRITT 1: Onclick-Attribut auf die Schaltfläche GetToken Funktion aufzurufen.

SCHRITT 2 und SCHRITT 3:

client-side:

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:

Ich habe verschiedene Methoden verwendet, um alle Parameterwerte benötigt bauen für die Token-Anfrage. Die ersten drei Builds: Authentifizierung, Transaktionsdetails, transparente Umleitung. Ich halte URLs und Payflow-Kontoinformationen in einer web.config-Datei. Die letzte Methode, ProcessTokenTransaction, führt alle schweren Aufgaben aus, um über WebRequest Kontakt mit Paypal aufzunehmen und es dann in die URL zu analysieren, die an den Client zurückgesendet wird. Diese Methode sollte für eine sauberere Lieferung überarbeitet werden, aber das überlasse ich Ihnen. ParseResponse ist eine Methode, die ein von mir erstelltes einfaches Modell auffüllt und dieses Modell zurückgibt.

URL für Token (Sandbox):https://pilot-payflowpro.paypal.com

DIES IST ALS DIE TOKEN URL DIFFERENT !! Wird im PaypalTranactionAPI-Konfigurationswert verwendet.

URL für Transaktion: (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; 
    } 

Schritt 4 und Schritt 5:

Zurück zur Client-Seite:

Hier verwende ich die URL gebaut aus den vorherigen Schritten und fügen Sie die letzten benötigten Parameter (sichere Kreditkarteninformationen) mit jQuery und dann REDIRECT t hinzu 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);    
} 

STEP 6:

Paypal wird auf eine der folgenden Methoden Post zurück: Abbrechen, Fehler oder Return (nennen Sie die Methoden alles, was Sie in der Token-Anfrage wollen). Parsen Sie die Antwort und schauen Sie sich die von Paypal zurückgegebenen Variablen an, insbesondere RESULT und RESPMSG. Lesen Sie die Dokumentation für Details, da Sie die Adressvalidierung und eine Reihe weiterer Funktionen integrieren können. Zeigen Sie anhand der Antwort an, was angemessen ist.

Server-Seite:

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); 
    } 

Hope this, und viel Glück hilft! Ich beantworte Klärungsfragen so wie ich kann. Vielen Dank für das Auschecken, und denken Sie daran, es zu bezahlen.

+1

Haben Sie in der Rücksende-URL eine Validierung vorgenommen, bevor Sie die Zahlung fortführen? wie zum Beispiel die Validierung, dass es sich um eine tatsächliche Transaktion handelt, und jemand hat nicht einfach eine Rückkehr-URL erstellt. – Justin

+1

Danke für Ihre Lösung. Das funktioniert für mich, aber ich musste im Verwaltungskonto 'Sicheres Token aktivieren' auf 'Wahr' setzen, damit dies funktioniert. Musstest du das auch machen? – mridula