2015-02-26 13 views
7

Tôi đang làm việc trên một ứng dụng C# VS2012 Framework 4.5 MVC đang cố gắng để trở thành PCI tuân thủ bằng cách sử dụng Payflow Pro (https://pilot-payflowpro.paypal.com). Chúng tôi đã sử dụng PayflowPro trong nhiều năm, và đây là những gì tôi phải sử dụng. Từ đọc sách của tôi có vẻ như tôi nên sử dụng chuyển hướng trong suốt vì vậy tôi không gửi bất cứ điều gì tư nhân cho máy chủ web của tôi, mặc dù tôi không biết nếu tôi cần điều đó với cách tôi hy vọng để xử lý này. Tôi cũng có một vài câu hỏi ...Paypal Payflow Transparent Redirect, SecureToken với AJAX?

Tôi nghĩ điều này hoạt động như thế nào: Sự hiểu biết của tôi là bạn cần một securetoken (giao tiếp với Paypal, chuyến đi 1). Sau đó, bạn đăng dữ liệu an toàn (CC, exp, mã bảo mật) bao gồm cả securetoken (giao tiếp với Paypal, chuyến đi 2) và nhận được ủy quyền và transactionID của việc bán hàng.

Tôi hy vọng sẽ làm điều đó: Tôi dự định có biểu mẫu có tất cả thông tin (chi tiết người dùng, chi tiết giao hàng và thông tin CC) và khi người dùng nhấn nút mua , Tôi sẽ sử dụng AJAX để xử lý chuyến đi 1 đến máy chủ của tôi (không có thông tin người dùng an toàn nào được gửi). Ở đây tôi sẽ tạo URL + params và gửi paypal thông tin un/pw của tôi để lấy mã thông báo (tất cả từ máy chủ của tôi). Câu trả lời sẽ được trả lại cho máy khách và, nếu thành công, sau đó tôi sẽ giao tiếp trực tiếp qua AJAX với máy chủ Cổng của Paypal, lần này gửi thông tin CC an toàn + mã thông báo (chuyến đi # 2). Dựa trên phản hồi cho chuyến đi # 2, tôi sẽ cho người dùng biết điều gì đang xảy ra với giao dịch mua của họ. Chuyến đi 2 không cần thông tin UN/PW Paypal của tôi vì nó có thể dễ dàng được nhìn thấy trên máy khách và tôi bao gồm SecureToken NÊN xác định giao dịch ban đầu. Từ những gì tôi đã giải thích, tôi không thấy cần chuyển hướng trong suốt. Hay tôi đang thiếu thứ gì đó ở đây?

Ngoài ra, tôi muốn sử dụng Loại giao dịch nào? Tạo 'Ủy quyền' cho chuyến đi # 1, sau đó là 'Bán' cho chuyến đi # 2?

Vì vậy, đây là nitty gritty loại mã hóa thứ: Để thử nghiệm D R & của tôi Tôi đang xây dựng của riêng chuỗi tham số cặp tên/giá trị của tôi (xem dưới đây) và giao tiếp với các máy chủ gateway qua WebRequest qua sandbox của họ/url kiểm tra (pilot-payflowpro.paypal.com). Tôi nhận được phản hồi thành công và SECURETOKEN trở lại. Yêu cầu ban đầu (được hiển thị bên dưới) cho mã thông báo bảo mật là TRXTYPE = A (Ủy quyền), không có thông tin thẻ nào được gửi. Tôi có muốn ủy quyền trước không?

Dưới đây là thông số của tôi (có thể bao gồm thông tin shipto là tốt, nhưng nó không được liệt kê dưới đây):

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 

Như tôi đã nói, tôi nhận được một phản ứng thành công và chuyển sang bước tiếp theo của việc gửi dữ liệu an toàn (CC#, EXPDATE, mã bảo mật). Khi tôi xóa thông tin UN/PW/VENDOR/Partner khỏi các tham số, tôi gặp lỗi do xác thực người dùng không hợp lệ. Nhưng, nhìn thấy tôi đang tự động xây dựng cuộc gọi thứ 2 này tôi không thể có paypal của tôi un/pw ở đó. Tôi đang thiếu gì? Bất cứ ai cũng hỗ trợ với điều này hoặc các câu hỏi khác từ trên cao?

Vui lòng cho tôi biết nếu tôi cần thêm thông tin làm rõ. Cảm ơn trước cho thời gian của bạn!

+0

Xem tài liệu ở đây: https: //developer.paypal.com/docs/classic/payflow/hướng dẫn tích hợp/# about-the-secure-token "Máy chủ cổng liên kết ID của bạn với mã bảo mật và trả về mã thông báo dưới dạng chuỗi gồm 32 ký tự chữ và số. chuyển dữ liệu giao dịch đến trang thanh toán được lưu trữ, bạn chuyển mã thông báo bảo mật và ID mã thông báo an toàn trong bài đăng biểu mẫu HTTP. Mã thông báo và ID kích hoạt máy chủ Cổng để truy xuất dữ liệu của bạn và hiển thị nó để khách hàng chấp thuận. " Chúng tôi sử dụng giỏ hàng tự trồng của mình nên tôi không sử dụng các trang HOSTED, có lẽ đây là vấn đề của tôi? – RichieMN

+0

SEEMS sử dụng phương pháp này bạn được yêu cầu bao gồm thông tin xác thực với mỗi yêu cầu. Nhìn vào REST API của Paypal. Tôi sẽ tạo một câu hỏi/nhận xét khác với những gì tôi đã học ... – RichieMN

+0

Hmmm. Tôi chỉ cố gắng thực hiện điều này và nó không hoạt động. Khi tôi chuyển hướng đến URL payflowlink, nó phản hồi với HTTP200 và không có nội dung HTML (và không có chuyển hướng). Tôi đã nói chuyện với PayPal hỗ trợ kỹ thuật, và họ nói rằng trình tự này là không thể: các hình thức đầu vào thẻ tín dụng phải được lưu trữ trên máy chủ paypal để sử dụng payflowlink (sử dụng một iFrame để nhúng nó trên trang web của chúng tôi). Tôi được chuyển hướng đến API DoDirectPayment. Sẽ mất một thời gian để tạo ra một thử nghiệm. – Owen

Trả lời

3

Tôi đã có thể sử dụng câu trả lời của RichieMN để làm việc Chuyển hướng trong suốt đang hoạt động. Tuy nhiên, sự cố khi thực hiện chuyển hướng với window.location.replace trong các chức năng SendCCDetailsToPaypal là bạn đang chuyển dữ liệu trên chuỗi GET.

Điều này hoạt động trên cổng PayFlow Gateway, nhưng khi họ gửi trình duyệt của khách hàng về ResponseURL của bạn, nhật ký Apache của bạn sẽ hiển thị URL toàn bộ payflowlink.paypal.com , bao gồm chuỗi GET làm liên kết giới thiệu trong Apache của bạn truy cập nhật ký! Chuỗi GET đó bao gồm số thẻ tín dụng và bây giờ bạn đã bị mất PCI của bạn tuân thủ!

Để giảm bớt vấn đề này, bạn có thể đặt SecureToken và SecureTokenID vào mẫu đăng ký thẻ tín dụng của bạn, và sau đó trực tiếp đến payflowlink.paypal.com, hoặc bạn có thể viết lại SendCCDetailsToPaypal chức năng để xây dựng một hình thức trình nó, như thế này:

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(); 
} 

Kể từ khi hình thức mà chuyển dữ liệu qua POST, khi máy chủ của bạn được POST kết quả trở lại, tham chiếu không chứa bất kỳ dữ liệu nhạy cảm, và tuân thủ PCI của bạn được duy trì.

+0

Rất vui, cảm ơn! – RichieMN

6

Sau khi dành nhiều thời gian với kỹ sư Paypal, tôi đã tìm ra giải pháp cho Payflow Transparent Redirect của Paypal mà không có trang được lưu trữ (có trang thanh toán riêng). Một lần nữa, đây là tài liệu mà, theo kỹ sư, là khá khó hiểu: Payflow API Documentation. Ngoài ra, mã không được tối ưu hóa vì nó chỉ là một ứng dụng R & D, nhưng nói chung, nó đang làm việc cho tôi. Chỉ là một ví dụ và giải thích, và tôi chắc chắn có những cách tốt hơn để thực hiện các bước riêng lẻ. Hy vọng điều này sẽ giúp và cho phép bạn bỏ qua một số rào chắn đã làm chậm quá trình tích hợp Paypal Payflow của bạn.

CÓ, PCI tuân thủ trong đó không có dữ liệu khách hàng an toàn nào sẽ tấn công vào máy chủ của riêng bạn. Hãy nhớ rằng sự tuân thủ PCI là khá phức tạp và có liên quan nhưng đây là một phần lớn của nó. Ok, vì vậy tôi sẽ giải thích những gì tôi đã làm để thực hiện công việc này trong môi trường MVC C#. Tôi sẽ giải thích các bước ở đây, sau đó bao gồm mã bên dưới.

  1. KHÁCH HÀNG: Khách hàng hoàn tất việc thêm mặt hàng vào giỏ hàng và nhấn nút MUA. Javascript xử lý nhấp chuột vào nút, không gửi và đưa bạn đến bước tiếp theo.
  2. KHÁCH HÀNG -> MÁY CHỦ: chức năng AJAX POSTS đến phương thức máy chủ để liên hệ với Paypal cho mã thông báo bảo mật dùng một lần. Giao tiếp này xác định BẠN (người bán) để paypal với xác thực của bạn, một id giao dịch duy nhất (một guid) và các chi tiết không an toàn về giao dịch (tổng cộng, thông tin thanh toán, thông tin giao hàng, chi tiết URL trả lại). Bằng cách này, tất cả thông tin acct cá nhân của người bán của bạn đều an toàn (máy chủ web đến Paypal).
  3. SERVER -> KHÁCH HÀNG: Từ giao dịch trên, bạn sẽ nhận được một chuỗi tham số có chứa mã bảo mật (trong số các công cụ khác, xem phương pháp có ví dụ). Sử dụng mẩu thông tin này, tôi tự động tạo url của mình mà cuối cùng tôi sẽ cần trên máy khách cho phần chuyển hướng trong suốt và gửi chuỗi url trở lại máy khách.
  4. KHÁCH HÀNG: Sử dụng url được trả lại ở bướC# 3, tôi hoàn thành URL bằng cách thêm các tham số thẻ tín dụng cần thiết bằng cách sử dụng jQuery.
  5. KHÁCH HÀNG -> PAYPAL: Đây là nơi tôi không hiểu phải làm gì. Trong khi bướC# 2 là một bài đăng, bước này sẽ là một REDIRECT. Chắc chắn, điều đó có vẻ thích hợp khi thấy nó được gọi là 'chuyển hướng trong suốt', nhưng phần đó không có ý nghĩa với tôi. Vì vậy, khi toàn bộ URL của bạn hoàn tất, bạn sẽ chuyển hướng cửa sổ đến Paypal để xử lý giao dịch của bạn theo nghĩa đen.
  6. PAYPAL -> SERVER: PayPal đăng lại một trong các URL bạn đã bao gồm trong bước 2 (đến phương thức công khai trên một trong các bộ điều khiển của tôi), và tôi đọc đối tượng phản hồi và phân tích cú pháp tham số.

Dễ dàng, phải không? Có lẽ, nhưng đối với tôi bước 5 gây ra cho tôi những vấn đề lớn. Tôi đã sử dụng POST và không hiểu tại sao tôi tiếp tục gặp lỗi về phản hồi. Đó là một trang html có thứ gì đó về một người bán hoặc xác thực không hợp lệ. Nhớ chuyển hướng, không đăng bài cho bướC# 5.

:

Bước 1: onclick thuộc tính trên nút để gọi GetToken chức năng.

Bước 2 và Bước 3:

client-side:

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:

Tôi đã phương pháp riêng biệt dùng để xây dựng tất cả các giá trị tham số cần thiết cho yêu cầu mã thông báo. Ba bản dựng đầu tiên: xác thực, chi tiết giao dịch, chuyển hướng trong suốt. Tôi giữ url và thông tin acct payflow trong một tập tin web.config. Phương thức cuối cùng, ProcessTokenTransaction, thực hiện tất cả việc nâng hạng nặng để liên hệ với Paypal thông qua WebRequest và sau đó phân tích nó thành URL sẽ được gửi lại cho máy khách. Phương pháp này nên được tái cấu trúc để phân phối sạch hơn, nhưng tôi sẽ để nguyên điều đó cho bạn. ParseResponse là một phương thức điền vào một mô hình đơn giản mà tôi đã tạo và trả về mô hình đó.

URL cho token (sandbox):https://pilot-payflowpro.paypal.com

NÀY khác với URL TOKEN !! Được sử dụng trong giá trị cấu hình PaypalTranactionAPI.

URL cho giao dịch: (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; 
    } 

BƯỚC 4 và Bước 5:

Back to Client Side:

Ở đây tôi sử dụng URL được xây dựng từ các bước trước và thêm thông số cần thiết cuối cùng (thông tin thẻ tín dụng an toàn) bằng cách sử dụng jQuery và sau đó ĐỔI MỚI 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);    
} 

Bước 6:

Paypal sẽ gửi về một trong những phương pháp sau đây: Hủy bỏ, Lỗi, hoặc Return (đặt tên cho phương pháp bất cứ điều gì bạn muốn trong yêu cầu token). Phân tích cú pháp phản hồi và xem xét các biến được trả lại từ Paypal, đặc biệt là RESULT và RESPMSG. Đọc tài liệu để biết chi tiết cụ thể vì bạn có thể kết hợp xác thực địa chỉ và một loạt các tính năng khác. Dựa trên phản hồi, hiển thị những gì phù hợp. bên

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); 
    } 

Hope this helps, và may mắn! Tôi sẽ trả lời các câu hỏi làm rõ khi tôi có thể. Cảm ơn bạn đã kiểm tra điều này, và nhớ trả nó về phía trước.

+1

bạn có thực hiện bất kỳ xác thực nào trong url trả về trước khi duy trì thanh toán không? chẳng hạn như xác nhận rằng đó là một giao dịch thực tế và một người nào đó không tạo ra một url trả về. – Justin

+1

Cảm ơn bạn đã giải pháp. Điều này phù hợp với tôi, nhưng tôi phải đặt 'bật mã thông báo an toàn' thành true trong tài khoản người quản lý để tính năng này hoạt động. Bạn có phải làm điều này không? – mridula