Проведя кучу времени с помощью инженера Paypal, я успешно рассмотрел решение для прозрачного переадресации Payflow Payflow Transparent Redirect без размещенных страниц (у вас есть страница оплаты). Опять же, вот документация, которая, по словам инженера, довольно запутанна: Payflow API Documentation. Кроме того, код не оптимизирован, так как это просто приложение R & D, но в целом оно работает для меня. Просто пример и объяснение, и я уверен, что есть лучшие способы сделать отдельные шаги. Надеемся, что это поможет и позволяет обойти некоторые из препятствий, которые замедляют интеграцию Payflow Payflow.
ДА, это соответствует требованиям PCI, поскольку никакие безопасные данные о клиентах не попадут на ваши собственные серверы. Помните, что соблюдение PCI довольно сложно и связано с этим, но это большая его часть. Итак, я объясню, что я сделал, чтобы сделать эту работу в среде MVC C#. Я объясню шаги здесь, а затем включу код ниже.
- КЛИЕНТ: Клиент заканчивает добавление товаров в корзину и нажимает кнопку «ПОКУПАТЬ». Javascript обрабатывает нажатие кнопки, не отправляет и переводит вас на следующий шаг.
- CLIENT -> SERVER: AJAX функция POSTS к серверному методу для связи с Paypal для одноразового защищенного токена. Это сообщение идентифицирует ВАС (торговца) с PayPal с вашей аутентификацией, уникальный идентификатор транзакции (guid guid) и небезопасные сведения о транзакции (общая сумма, информация о платежах, информация о доставке, данные о возврате URL-адреса). Таким образом, вся ваша информация о личных данных вашего продавца безопасна (веб-сервер для Paypal).
- СЕРВЕР -> КЛИЕНТ: Из транзакции выше вы получите строку параметров, содержащую защищенный токен (среди прочего, см. Метод с примером). Используя эту часть информации, я динамически создаю свой url, который мне в конечном итоге понадобится на клиенте для прозрачной части перенаправления, и отправьте строку url обратно клиенту.
- КЛИЕНТ: Используя URL-адрес, который был возвращен в шаге №3, я заполняю URL-адрес, добавляя необходимые параметры кредитной карты, используя jQuery.
- КЛИЕНТ -> PAYPAL: Здесь я не понял, что делать. В то время как шаг № 2 был сообщением, этот шаг будет REDIRECT. Конечно, это кажется уместным, потому что это называется «прозрачным перенаправлением», но эта часть просто не имела для меня смысла. Таким образом, как только весь URL-адрес будет завершен, вы будете буквально перенаправлять окно в Paypal для обработки транзакции.
- PAYPAL -> SERVER: PayPal отправляет сообщения обратно на один из URL-адресов, включенных в шаге 2 (публичному методу на одном из моих контроллеров), и я прочитал объект ответа и проанализировал параметры.
Легко, правда? Возможно, но для меня шаг 5 вызвал у меня большие проблемы. Я использовал POST и не понимал, почему я продолжал получать ошибки в ответе. Это была html-страница с чем-то о недействительном продавце или аутентификации. Не забудьте перенаправить, а не отправить для шага №5.
КОД:
ШАГ 1: OnClick атрибут на кнопку, чтобы вызвать функцию GetToken.
ШАГ 2 и ШАГ 3:
стороне клиента:
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
});}
стороне сервера:
я отдельные методы, используемые для построения всех значений параметров необходимо для запроса маркера. Первые три сборки: аутентификация, сведения о транзакции, прозрачная переадресация. Я сохраняю URL-адрес и информацию о расходах в файле web.config. Последний метод ProcessTokenTransaction выполняет все тяжелые операции, чтобы связаться с Paypal через WebRequest, а затем проанализировать его в URL-адрес, который будет отправлен обратно клиенту. Этот метод должен быть реорганизован для более чистой доставки, но я оставлю это до вас. ParseResponse - это метод, который заполняет простую модель, которую я создал, и возвращает эту модель.
URL для маркеров (песочница):https://pilot-payflowpro.paypal.com
ЭТО отличается от URL TOKEN !! Используется в значении конфигурации PaypalTranactionAPI.
URL для сделки: (песочница)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;
}
ШАГ 4 и Шаг 5:
Назад к стороне клиента:
Здесь я использую URL встроенный с предыдущих шагов и добавьте окончательные необходимые параметры (данные защищенной кредитной карты) с помощью jQuery, а затем 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);
}
ШАГ 6:
Paypal разместит назад к одному из следующих способов: Отменить, Error или Return (имя методы, что вы хотите в знак запроса). Разберите ответ и посмотрите на переменные, возвращаемые из Paypal, в частности, RESULT и RESPMSG. Прочтите документацию по специфике, так как вы можете включить проверку адреса и множество других функций. На основе ответа отобразите, что подходит. сторона
сервера:
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);
}
Надеется, что это помогает, и удаче! Я отвечу на вопросы по разъяснению, насколько смогу. Спасибо, что проверили это, и не забудьте оплатить его.
Глядя на документ, расположенный здесь: https: //developer.paypal.com/docs/classic/payflow/integration-guide/# about-the-secure-token «Сервер шлюза связывает ваш идентификатор с защищенным маркером и возвращает токен в виде строки длиной до 32 буквенно-цифровых символов. To передайте данные транзакции на страницу проверочных проверок, вы передаете безопасный токен и безопасный идентификатор маркера в сообщении формы HTTP. Токен и идентификатор запускают сервер шлюза для извлечения ваших данных и отображения его для утверждения клиентами ». Мы используем нашу собственную домашнюю корзину для покупок, поэтому я не использую страницы HOSTED, возможно, это моя проблема? – RichieMN
ПОСМОТРЕТЬ, что с помощью этого метода вам необходимо включать данные аутентификации с каждым запросом. Загляните в API REST Paypal. Я создам еще один вопрос/комментарий с тем, что Iearn ... – RichieMN
Хммм. Я просто пытался реализовать это, и он не работает. Когда я перенаправляю URL-адрес payflowlink, он отвечает HTTP200 и HTML-телом (и не перенаправляет). Я говорил с технической поддержкой PayPal, и они говорят, что эта последовательность невозможна: форма ввода кредитной карты должна размещаться на сервере PayPal для использования payflowlink (с помощью iFrame для его внедрения на нашем сайте). Я был направлен в DoDirectPayment API. Потребуется некоторое время, чтобы развить тест. – Owen