Я работаю над приложением MVC C # VS2012 Framework 4.5, которое пытается стать совместимым с PCI с помощью Payflow Pro (https: //pilot-payflowpro.paypal .com). Мы используем PayflowPro годами, и это то, что мне нужно использовать. Из моего чтения кажется, что я должен использовать Transparent Redirect, поэтому я не размещаю ничего личного на своем веб-сервере, хотя я не знаю, нужно ли мне это с тем, как я надеюсь справиться с этим. Еще у меня есть несколько вопросов ...
Как я думаю, все это работает: Насколько я понимаю, вам нужен securetoken (связь с Paypal, поездка 1). Затем вы публикуете защищенные данные (CC, exp, код безопасности), включая securetoken (связь с Paypal, поездка 2), и получаете авторизацию и идентификатор транзакции продажи.
Как я надеюсь это сделать: Я собираюсь создать форму, в которой будет вся информация (данные пользователя, сведения о доставке и информация CC), и когда пользователь нажимает кнопку покупки, я буду использовать AJAX для обработки поездки 1 на мой сервер (нет безопасного информация о пользователе отправлена). Здесь я создам URL + params и отправлю PayPal мою информацию un / pw, чтобы получить токен (все с моего сервера). Ответ будет возвращен клиенту, и, в случае успеха, я буду напрямую общаться через AJAX с сервером шлюза Paypal, на этот раз отправив защищенный токен CC info + (поездка № 2). Основываясь на ответе на поездку №2, я сообщу пользователю, что случилось с его покупкой. Для поездки 2 не нужна моя информация Paypal UN / PW, поскольку ее можно легко увидеть на клиенте, и я включаю SecureToken, который ДОЛЖЕН идентифицировать исходную транзакцию. Из того, что я объяснил, я не вижу необходимости в прозрачном перенаправлении. Или мне что-то здесь не хватает?
Кроме того, какой тип транзакции я хочу использовать? Создать «Авторизацию» для поездки №1, а затем «Распродажу» для поездки №2?
Итак, вот самые мелкие детали типа кодирования: Для своих исследований и разработок я создаю свою собственную строку параметров пары имя / значение (см. Ниже) и связываюсь с сервером шлюза через WebRequest через их песочницу / тестовый URL (pilot-payflowpro.paypal.com). Я получаю успешный ответ и возвращаю SECURETOKEN. Первоначальный запрос (показанный ниже) для безопасного токена - TRXTYPE = A (авторизация), информация о карте не отправляется. Я хочу сначала авторизоваться?
Вот мои параметры (может также включать информацию о доставке, но ее нет в списке ниже):
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=myemail@somedomain.com
&CURRENCY=USD
**&TRXTYPE=A**
&SILENTTRAN=TRUE
&CREATESECURETOKEN=Y
&SECURETOKENID=a99998afe2474b1b82c8214c0824df99
Как я уже сказал, я получаю успешный ответ и перехожу к следующему этапу отправки защищенных данных (CC #, EXPDATE, код безопасности). Когда я удаляю информацию о своем UN / PW / VENDOR / Partner из параметров, я получаю сообщение об ошибке из-за неправильной аутентификации пользователя. Но, видя, что я динамически создаю этот второй вызов, у меня не может быть там мой PayPal un / pw. Что мне не хватает? Кто-нибудь предлагает помощь с этим или другими вопросами сверху?
Пожалуйста, дайте мне знать, если мне нужно добавить какие-либо пояснения. Спасибо заранее за ваше время!
2 ответа
Я смог использовать ответ RichieMN, чтобы получить работающее прозрачное перенаправление. Однако проблема с перенаправлением с помощью window.location.replace в функции SendCCDetailsToPaypal заключается в том, что вы передаете данные в строке GET.
Это работает на стороне шлюза PayFlow, но когда они отправляют браузер клиента обратно на ваш ResponseURL, в ваших журналах Apache будет отображаться весь URL-адрес payflowlink.paypal.com, включая строку GET в качестве реферера в вашем Журналы доступа Apache! Эта строка GET включает номер кредитной карты, и теперь вы только что потеряли соответствие PCI!
Чтобы решить эту проблему, вы можете либо поместить SecureToken и SecureTokenID в форму ввода кредитной карты и отправить их непосредственно на payflowlink.paypal.com, либо вы можете переписать функцию SendCCDetailsToPaypal , чтобы создать форму и отправьте его, например:
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();
}
Поскольку эта форма передает данные через POST, когда ваш сервер получает результат POST, реферер не содержит никаких конфиденциальных данных, и ваше соответствие PCI сохраняется.
Проведя кучу времени с инженером Paypal, я успешно нашел решение для Payflow Transparent Redirect без размещенных страниц (с собственной платежной страницей). Опять же, вот документация, которая, по мнению инженера, довольно запутанная: Документация по API Payflow.. Кроме того, код не оптимизирован, поскольку это было всего лишь приложение для исследований и разработок, но в целом оно работает на меня. Просто пример и объяснение, и я уверен, что есть более эффективные способы выполнения отдельных шагов. Надеюсь, это поможет и позволит вам обойти некоторые препятствия, которые замедляют вашу интеграцию Paypal Payflow.
ДА, он соответствует стандарту PCI в том смысле, что никакие защищенные данные клиентов не попадут на ваши собственные серверы. Помните, что соблюдение PCI - это довольно сложно и сложно, но это большая часть. Хорошо, я объясню, что я сделал, чтобы заставить эту работу работать в среде MVC C #. Я объясню шаги здесь, а затем включу код ниже.
- КЛИЕНТ: Клиент завершает добавление товаров в корзину и нажимает кнопку КУПИТЬ. Javascript обрабатывает нажатие кнопки, не отправляет и переводит вас к следующему шагу.
- КЛИЕНТ -> СЕРВЕР: функция AJAX ОТПРАВЛЯЕТ метод сервера, чтобы связаться с Paypal за одноразовым токеном безопасности. Это сообщение идентифицирует ВАС (торговца) для PayPal с вашей аутентификацией, уникальным идентификатором транзакции (guid) и незащищенными деталями транзакции (общая сумма, информация о выставлении счетов, информация о доставке, детали URL-адреса возврата). Таким образом, вся информация о вашем личном аккаунте продавца будет в безопасности (от веб-сервера до Paypal).
- СЕРВЕР -> КЛИЕНТ: из транзакции выше вы получите строку параметра, содержащую защищенный токен (среди прочего, см. Метод с примером). Используя эту информацию, я динамически создаю свой URL-адрес, который мне в конечном итоге понадобится на клиенте для части прозрачного перенаправления, и отправляю строку URL-адреса обратно клиенту.
- КЛИЕНТ: Используя URL-адрес, который был возвращен на шаге № 3, я завершаю URL-адрес, добавляя необходимые параметры кредитной карты с помощью jQuery.
- КЛИЕНТ -> PAYPAL: Здесь я не понял, что делать. Хотя шаг № 2 был опубликован, этот шаг будет ПЕРЕПРАВИЛЬНЫМ. Конечно, это кажется уместным, учитывая, что это называется «прозрачное перенаправление», но эта часть просто не имела для меня смысла. Итак, как только ваш URL-адрес будет заполнен, вы буквально перенаправите окно на Paypal для обработки вашей транзакции.
- PAYPAL -> СЕРВЕР: PayPal отправляет сообщение обратно на один из URL-адресов, которые вы указали на шаге 2 (общедоступный метод на одном из моих контроллеров), и я читаю объект ответа и анализирую параметры.
Легко, правда? Возможно, но для меня шаг 5 вызвал большие проблемы. Я использовал POST и не понимал, почему я продолжаю получать ошибки в ответе. Это была html-страница с информацией о недействительном продавце или аутентификации. Не забудьте перенаправить, а не публиковать для шага 5.
< Сильный > CODE :
ШАГ 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-адреса ТОКЕНА !! Используется в значении конфигурации 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, а затем ПЕРЕНАПРАВЛЯЮ в 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 отправит ответ одним из следующих методов: Отмена, Ошибка или Возврат (назовите методы как хотите в запросе токена). Проанализируйте ответ и посмотрите на переменные, возвращаемые 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);
}
Надеюсь, что это помогает и удачи! Я отвечу на уточняющие вопросы, если смогу. Спасибо, что посмотрели это, и не забудьте заплатить вперед.
Похожие вопросы
Новые вопросы
ajax
AJAX (асинхронный JavaScript и XML) — это метод создания интерактивных пользовательских интерфейсов веб-сайтов без традиционного обновления или перезагрузки веб-страницы. Он использует асинхронный обмен данными между клиентом и сервером, чтобы обновлять отображаемую информацию и беспрепятственно реагировать на взаимодействие с пользователем. Включите дополнительные теги для языков программирования, библиотек, фреймворков, веб-браузеров, протоколов и другой информации об окружающей среде.