Po spędzeniu kilku godzin z inżynierem Paypal, udało mi się znaleźć rozwiązanie dla Paypal Payflow Transparent Redirect bez hostowanych stron (mają własną stronę płatności). Ponownie, oto dokumentacja, która według inżyniera jest dość myląca: Payflow API Documentation. Ponadto kod nie jest zoptymalizowany, ponieważ był to tylko aplikacja R & D, ale jako całość działa dla mnie. Tylko przykład i wyjaśnienie, i jestem pewien, że istnieją lepsze sposoby robienia indywidualnych kroków. Mam nadzieję, że to pomaga i pozwala ominąć niektóre blokady dróg, które spowalniały integrację z Paypal Payflow.
TAK, jest zgodna ze standardem PCI, ponieważ żadne bezpieczne dane klientów nie trafią na własne serwery. Pamiętaj, że zgodność z PCI jest dość skomplikowana i zaangażowana, ale jest to duża część tego. Ok, więc wyjaśnię, co zrobiłem, aby wykonać tę pracę w środowisku MVC C#. Wyjaśnię tutaj kroki, a następnie dołącz poniższy kod.
- KLIENT: Klient kończy dodawać pozycje do koszyka i naciska przycisk KUP. JavaScript obsługuje kliknięcie przycisku, nie przesyła i przechodzi do następnego kroku.
- KLIENT -> SERWER: Funkcja AJAX POSTS do metody serwera, aby skontaktować się z Paypal za bezpieczny token jednorazowy. Ta komunikacja identyfikuje użytkownika (kupca) z Paypal za pomocą Twojego uwierzytelnienia, unikalnego identyfikatora transakcji (identyfikatora) i niepoufnych danych dotyczących transakcji (suma, informacje rozliczeniowe, informacje o wysyłce, szczegóły dotyczące zwrotnego adresu URL). W ten sposób wszystkie twoje dane osobowe kupca są bezpieczne (serwer internetowy do Paypal).
- SERWER -> KLIENT: Z powyższej transakcji otrzymasz ciąg parametrów zawierający bezpieczny token (między innymi zobacz metodę z przykładem). Korzystając z tej informacji, dynamicznie tworzę mój adres URL, który w końcu będę potrzebował na kliencie dla przezroczystej części przekierowania, i wyślę ciąg URL do klienta.
- KLIENT: Korzystając z adresu URL, który został zwrócony w kroku 3, uzupełniam adres URL, dodając wymagane parametry karty kredytowej za pomocą jQuery.
- KLIENT -> PAYPAL: Tutaj nie rozumiem, co robić. Podczas gdy krok nr 2 był post, ten krok będzie REDIRECT. Jasne, wydaje się to właściwe, ponieważ nazywa się to "przezroczystym przekierowaniem", ale ta część nie ma dla mnie sensu. Tak więc, gdy cały adres URL zostanie ukończony, dosłownie przekierujesz okno do Paypal w celu przetworzenia transakcji.
- PAYPAL -> SERVER: PayPal odsyła z powrotem do jednego z adresów URL zawartych w kroku 2 (do publicznej metody na jednym z moich kontrolerów), a ja odczytuję obiekt odpowiedzi i analizuję parametry.
Łatwo, prawda? Być może, ale dla mnie krok 5 sprawił mi duże problemy. Używałem POST i nie rozumiałem, dlaczego ciągle dostaję błędy w odpowiedzi. Była to strona html zawierająca informacje o nieważnym sprzedawcy lub uwierzytelnieniu. Pamiętaj, aby przekierować, a nie publikować w kroku 5.
KOD:
KROK 1: atrybut onclick przycisku wywołać funkcję GetToken.
KROK 2 i KROK 3:
po stronie klienta:
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:
Mam potrzebne oddzielne metody stosowane do budowy wszystkich wartości parametrów dla żądania tokena. Pierwsze trzy kompilacje: uwierzytelnianie, szczegóły transakcji, przezroczyste przekierowanie. W plikach web.config przechowuję informacje o adresach URL i płatnościach. Ostatnia metoda, ProcessTokenTransaction, wykonuje wszystkie ciężkie operacje, aby skontaktować się z Paypal przez WebRequest, a następnie przeanalizować go pod adresem URL, który zostanie odesłany do klienta. Ta metoda powinna zostać refaktoryzowana w celu uzyskania czystszej dostawy, ale pozostawiam to tobie. ParseResponse to metoda zapełniająca prosty model, który utworzyłem i zwraca ten model.
URL tokenu (sandbox):https://pilot-payflowpro.paypal.com
Różni się to od tokena URL !! Używany w wartości konfiguracyjnej PaypalTranactionAPI.
URL dla transakcji: (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;
}
etapach 4 i 5:
Powrót do Side Client:
Tutaj używam URL wbudowanego z poprzednich kroków i dodaj ostatnie potrzebne parametry (informacje o bezpiecznej karcie kredytowej) za pomocą jQuery, a następnie 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);
}
KROK 6:
Paypal będzie zakładać z powrotem do jednej z następujących metod: Cancel, błędu lub Return (nazwa metod cokolwiek chcesz w żądaniu tokena). Przetwórz odpowiedź i spójrz na zmienne zwrócone z Paypal, w szczególności RESULT i RESPMSG. Zapoznaj się z dokumentacją, aby uzyskać szczegółowe informacje, ponieważ możesz włączyć sprawdzanie poprawności adresów i szereg innych funkcji. Na podstawie odpowiedzi wyświetl, co jest odpowiednie. strona
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);
}
Nadzieja to pomaga, i powodzenia! Odpowiem na pytania wyjaśniające, tak jak jestem w stanie. Dziękuję za sprawdzenie tego i pamiętaj, aby zapłacić dalej.
Patrząc na dokument znajdujący się tutaj: https: //developer.paypal.com/docs/classic/payflow/integration-guide/# about-the-secure-token "Serwer Gateway kojarzy Twój identyfikator z bezpiecznym tokenem i zwraca token jako ciąg maksymalnie 32 znaków alfanumerycznych To przekazać dane transakcji do hostowanej strony transakcji, przekazać bezpieczny token i bezpieczny token ID w formularzu HTTP. Token i identyfikator uruchamiają serwer Gateway, aby pobrać dane i wyświetlić je w celu zatwierdzenia przez klienta. " Używamy własnego domowego koszyka na zakupy, więc nie używam stron HOSTED, może to mój problem? – RichieMN
WYDAJE, że za pomocą tej metody musisz podać informacje uwierzytelniające dla każdego żądania. Zajrzyj do interfejsu REST API Paypal. Stworzę kolejne pytanie/komentarz z tym, czego się dowiem ... – RichieMN
Hmmm. Właśnie próbowałem to zaimplementować i to nie działa. Kiedy wykonuję przekierowanie do adresu URL payflowlink, odpowiada on za pomocą HTTP200 i bez treści HTML (i bez przekierowania). Rozmawiałem z obsługą techniczną systemu PayPal i twierdzą, że ta sekwencja nie jest możliwa: formularz wejściowy karty kredytowej musi być hostowany na serwerze PayPal, aby korzystać z usługi payflowlink (za pomocą ramki iFrame do osadzenia jej na naszej stronie). Zostałem skierowany do interfejsu API DoDirectPayment. Poświęcę trochę czasu na zrobienie testu. – Owen