2015-02-26 5 views
7

Я работаю над приложением C# VS2012 Framework 4.5 MVC, которое пытается стать совместимым с PCI, используя Payflow Pro (https://pilot-payflowpro.paypal.com). Мы используем PayflowPro в течение многих лет, и это то, что я должен использовать. Из моего чтения кажется, что я должен использовать Transparent Redirect, чтобы я не публиковал что-либо личное для своего веб-сервера, хотя я не знаю, нужно ли мне это с тем, как я надеюсь это обработать. У меня также есть несколько вопросов ...Paypal Payflow Transparent Redirect, SecureToken с AJAX?

Как я думаю, что это все работает: Я понимаю, что вам нужно securetoken (связь с Paypal, отключение 1). Затем вы публикуете защищенные данные (CC, exp, защитный код), включая securetoken (связь с Paypal, поездка 2) и получаете авторизацию и идентификатор транзакции продажи.

Как я надеюсь сделать это: Я намерен на иметь форму, которая будет иметь всю информацию (данные пользователя, судоходные детали, и CC данные), и когда пользователь нажимает на кнопку покупки , Я буду использовать AJAX для обработки поездки 1 на мой сервер (никакой защищенной информации пользователя не отправлено). Здесь я создам URL + params и отправлю paypal мою информацию un/pw, чтобы получить токен (все с моего сервера). Ответ будет возвращен клиенту, и, в случае успеха, я тогда напрямую свяжусь через AJAX с сервером шлюза Paypal, на этот раз отправив защищенный CC-ток + токен (trip # 2). Основываясь на ответе на поездку № 2, я дам пользователю понять, что случилось с их покупкой. Поездка 2 не нуждается в моей информации Paypal UN/PW, поскольку ее легко увидеть на клиенте, и я включаю SecureToken, который ДОЛЖЕН идентифицировать первоначальную транзакцию. Из того, что я объяснил, я не вижу необходимости в Transparent Redirect. Или я чего-то не хватает?

Также, какой тип транзакции я хочу использовать? Создайте «Авторизацию» для поездки №1, затем «Продажа» для поездки №2?

Так вот вшивый песчаный типа кодирования материал: Для моего R & D тестирования Я строю свою собственную строку имени/значение параметра пара (см ниже) и сообщающуюся с сервером шлюза с помощью WebRequest через песочницу/test url (pilot-payflowpro.paypal.com). Я получаю успешный ответ и SECURETOKEN обратно. Первоначальный запрос (показано ниже) для безопасного токена - TRXTYPE = A (авторизация), информация о карте не отправляется. Я хочу сначала авторизовать?

Вот мои параметры (может включать shipto информацию, а также, но его нет в список ниже):

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 

Как я уже сказал, я получаю успешный ответ и перейти к следующему шагу отправки защищенных данных (CC#, EXPDATE, код безопасности). Когда я удаляю свою информацию UN/PW/VENDOR/Partner из параметров, я получаю сообщение об ошибке из-за неправильной аутентификации пользователя. Но, видя, что я динамически строю этот второй звонок, я не могу иметь свой paypal un/pw. Что мне не хватает? Кто-нибудь предлагает помощь по этим или другим вопросам сверху?

Пожалуйста, дайте мне знать, если мне нужно уточнить, что нужно добавить. Спасибо заранее за ваше время!

+0

Глядя на документ, расположенный здесь: https: //developer.paypal.com/docs/classic/payflow/integration-guide/# about-the-secure-token «Сервер шлюза связывает ваш идентификатор с защищенным маркером и возвращает токен в виде строки длиной до 32 буквенно-цифровых символов. To передайте данные транзакции на страницу проверочных проверок, вы передаете безопасный токен и безопасный идентификатор маркера в сообщении формы HTTP. Токен и идентификатор запускают сервер шлюза для извлечения ваших данных и отображения его для утверждения клиентами ». Мы используем нашу собственную домашнюю корзину для покупок, поэтому я не использую страницы HOSTED, возможно, это моя проблема? – RichieMN

+0

ПОСМОТРЕТЬ, что с помощью этого метода вам необходимо включать данные аутентификации с каждым запросом. Загляните в API REST Paypal. Я создам еще один вопрос/комментарий с тем, что Iearn ... – RichieMN

+0

Хммм. Я просто пытался реализовать это, и он не работает. Когда я перенаправляю URL-адрес payflowlink, он отвечает HTTP200 и HTML-телом (и не перенаправляет). Я говорил с технической поддержкой PayPal, и они говорят, что эта последовательность невозможна: форма ввода кредитной карты должна размещаться на сервере PayPal для использования payflowlink (с помощью iFrame для его внедрения на нашем сайте). Я был направлен в DoDirectPayment API. Потребуется некоторое время, чтобы развить тест. – Owen

ответ

3

Я смог использовать ответ RichieMN, чтобы получить рабочий Transparent Redirect. Однако проблема с выполнением перенаправления с window.location.replace в функции SendCCDetailsToPaypal заключается в том, что вы передаете данные в строке GET.

Это работает на стороне Payflow шлюза, но когда они посылают браузер клиента обратно на ResponseURL, ваши журналы Apache покажут весь payflowlink.paypal.com URL, в том числе 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 поддерживается.

+0

Хороший улов, спасибо! – RichieMN

6

Проведя кучу времени с помощью инженера Paypal, я успешно рассмотрел решение для прозрачного переадресации Payflow Payflow Transparent Redirect без размещенных страниц (у вас есть страница оплаты). Опять же, вот документация, которая, по словам инженера, довольно запутанна: Payflow API Documentation. Кроме того, код не оптимизирован, так как это просто приложение R & D, но в целом оно работает для меня. Просто пример и объяснение, и я уверен, что есть лучшие способы сделать отдельные шаги. Надеемся, что это поможет и позволяет обойти некоторые из препятствий, которые замедляют интеграцию Payflow Payflow.

ДА, это соответствует требованиям PCI, поскольку никакие безопасные данные о клиентах не попадут на ваши собственные серверы. Помните, что соблюдение PCI довольно сложно и связано с этим, но это большая его часть. Итак, я объясню, что я сделал, чтобы сделать эту работу в среде MVC C#. Я объясню шаги здесь, а затем включу код ниже.

  1. КЛИЕНТ: Клиент заканчивает добавление товаров в корзину и нажимает кнопку «ПОКУПАТЬ». Javascript обрабатывает нажатие кнопки, не отправляет и переводит вас на следующий шаг.
  2. CLIENT -> SERVER: AJAX функция POSTS к серверному методу для связи с Paypal для одноразового защищенного токена. Это сообщение идентифицирует ВАС (торговца) с PayPal с вашей аутентификацией, уникальный идентификатор транзакции (guid guid) и небезопасные сведения о транзакции (общая сумма, информация о платежах, информация о доставке, данные о возврате URL-адреса). Таким образом, вся ваша информация о личных данных вашего продавца безопасна (веб-сервер для Paypal).
  3. СЕРВЕР -> КЛИЕНТ: Из транзакции выше вы получите строку параметров, содержащую защищенный токен (среди прочего, см. Метод с примером). Используя эту часть информации, я динамически создаю свой url, который мне в конечном итоге понадобится на клиенте для прозрачной части перенаправления, и отправьте строку url обратно клиенту.
  4. КЛИЕНТ: Используя URL-адрес, который был возвращен в шаге №3, я заполняю URL-адрес, добавляя необходимые параметры кредитной карты, используя jQuery.
  5. КЛИЕНТ -> PAYPAL: Здесь я не понял, что делать. В то время как шаг № 2 был сообщением, этот шаг будет REDIRECT. Конечно, это кажется уместным, потому что это называется «прозрачным перенаправлением», но эта часть просто не имела для меня смысла. Таким образом, как только весь URL-адрес будет завершен, вы будете буквально перенаправлять окно в Paypal для обработки транзакции.
  6. 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); 
    } 

Надеется, что это помогает, и удаче! Я отвечу на вопросы по разъяснению, насколько смогу. Спасибо, что проверили это, и не забудьте оплатить его.

+1

Вы делали какие-либо проверки в обратном URL-адресе, прежде чем продолжать платеж? например, подтверждение того, что это фактическая транзакция, а кто-то просто не создал обратный URL-адрес. – Justin

+1

Спасибо за ваше решение. Это работает для меня, но я должен был установить «включить безопасный токен» в true в учетной записи менеджера, чтобы это работало. Вам тоже нужно было это сделать? – mridula

Смежные вопросы