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.
- 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.
- 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).
- 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.
- CLIENT: Utilizzando l'url restituito nel passaggio n. 3, ho completato l'URL aggiungendo i parametri della carta di credito necessari utilizzando jQuery.
- 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.
- 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.
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
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
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