2013-06-02 25 views
6

Tôi đang cố gắng gọi PayPal api từ mã của tôi. Tôi thiết lập tài khoản sandbox và nó hoạt động khi tôi sử dụng curl nhưng mã của tôi không hoạt động theo cùng một cách, thay vào đó trả lại 401 Unauthorized.Paypal REST api gọi hoạt động từ cURL nhưng không phải từ mã C#

Đây là lệnh curl như documented by Paypal

curl https://api.sandbox.paypal.com/v1/oauth2/token -H "Accept: application/json" -H "Accept-Language: en_US" -u "A****:E****" -d "grant_type=client_credentials" 

UPDATE: Rõ ràng .Credentials không làm các trick, thay vì thiết lập Authorization tiêu đề bằng tay làm việc (xem code)

Dưới đây là đoạn code (tỉa về bản chất của nó):

HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://api.sandbox.paypal.com/v1/oauth2/token"); 
    request.Method = "POST"; 
    request.Accept = "application/json"; 
    request.Headers.Add("Accept-Language:en_US") 

    // this doesn't work: 
    **request.Credentials = new NetworkCredential("A****", "E****");** 

    // DO THIS INSTEAD 
    **string authInfo = Convert.ToBase64String(System.Text.Encoding.Default.GetBytes("A****:E****"));** 
    **request.Headers["Authorization"] = "Basic " + authInfo;** 

    using (StreamWriter swt = new StreamWriter(request.GetRequestStream())) 
    { 
    swt.Write("grant_type=client_credentials"); 
    } 

    request.BeginGetResponse((r) => 
    { 
    try 
    { 
     HttpWebResponse response = request.EndGetResponse(r) as HttpWebResponse; // Exception here 
     .... 
    } catch (Exception x) { .... } // log the exception - 401 Unauthorized 
    }, null); 

Đây là yêu cầu f đang rom bắt bởi Fiddler (thô), không có thông số cho phép đối với một số lý do:

POST https://api.sandbox.paypal.com/v1/oauth2/token HTTP/1.1 
Accept: application/json 
Accept-Language: en_US 
Host: api.sandbox.paypal.com 
Content-Length: 29 
Expect: 100-continue 
Connection: Keep-Alive 

grant_type=client_credentials 
+0

Có một không gian thiếu trong chấp nhận tiêu đề nhưng tôi không thể nhìn thấy bất cứ thứ gì rõ ràng. Bạn đã thử chụp hai yêu cầu để xem có gì khác biệt không, ví dụ: sử dụng Wireshark hoặc một proxy như Fiddler? – Rup

+0

@Rup Tôi đã thử với Fiddler, vẫn gặp khó khăn trong nắm bắt được yêu cầu curl nhưng yêu cầu mã không chứa header Auth (xem cập nhật) –

+1

Có một số thư viện HTTP ví dụ Apache sẽ không gửi thông tin đăng nhập trừ khi được yêu cầu bởi máy chủ từ xa, nhưng tôi không biết .NET cũng vậy. Hoặc ít nhất nó phải trả lời 401 cho họ. Có thể có một cách để buộc nó quá vào đối tượng yêu cầu? – Rup

Trả lời

3

này việc sử dụng HttpClient ... 'RequestT' là một chung cho các đối số yêu cầu PayPal, tuy nhiên nó không được sử dụng . 'ResponseT' được sử dụng và nó là phản hồi từ PayPal theo tài liệu của họ.

Lớp 'PayPalConfig' đọc clientid và bí mật từ tệp web.config bằng ConfigurationManager. Điều cần nhớ là đặt tiêu đề Cấp quyền thành "Cơ bản" KHÔNG "Vòng bi" và nếu và xây dựng đúng đối tượng 'StringContent' với loại phương tiện phù hợp (x-www-form-urlencoded).

//gets PayPal accessToken 
    public async Task<ResponseT> InvokePostAsync<RequestT, ResponseT>(RequestT request, string actionUrl) 
    { 
     ResponseT result; 

     // 'HTTP Basic Auth Post' <http://stackoverflow.com/questions/21066622/how-to-send-a-http-basic-auth-post> 
     string clientId = PayPalConfig.clientId; 
     string secret = PayPalConfig.clientSecret; 
     string oAuthCredentials = Convert.ToBase64String(Encoding.Default.GetBytes(clientId + ":" + secret)); 

     //base uri to PayPAl 'live' or 'stage' based on 'productionMode' 
     string uriString = PayPalConfig.endpoint(PayPalConfig.productionMode) + actionUrl; 

     HttpClient client = new HttpClient(); 

     //construct request message 
     var h_request = new HttpRequestMessage(HttpMethod.Post, uriString); 
     h_request.Headers.Authorization = new AuthenticationHeaderValue("Basic", oAuthCredentials); 
     h_request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 
     h_request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue("en_US")); 

     h_request.Content = new StringContent("grant_type=client_credentials", UTF8Encoding.UTF8, "application/x-www-form-urlencoded"); 

     try 
     { 
      HttpResponseMessage response = await client.SendAsync(h_request); 

      //if call failed ErrorResponse created...simple class with response properties 
      if (!response.IsSuccessStatusCode) 
      { 
       var error = await response.Content.ReadAsStringAsync(); 
       ErrorResponse errResp = JsonConvert.DeserializeObject<ErrorResponse>(error); 
       throw new PayPalException { error_name = errResp.name, details = errResp.details, message = errResp.message }; 
      } 

      var success = await response.Content.ReadAsStringAsync(); 
      result = JsonConvert.DeserializeObject<ResponseT>(success); 
     } 
     catch (Exception) 
     { 
      throw new HttpRequestException("Request to PayPal Service failed."); 
     } 

     return result; 
    } 

QUAN TRỌNG: sử dụng Tác vụ.WhenAll() để đảm bảo kết quả.

// gets access token with HttpClient call..and ensures there is a Result before continuing 
    // so you don't try to pass an empty or failed token. 
    public async Task<TokenResponse> AuthorizeAsync(TokenRequest req) 
    { 
     TokenResponse response; 
     try 
     { 
      var task = new PayPalHttpClient().InvokePostAsync<TokenRequest, TokenResponse>(req, req.actionUrl); 
      await Task.WhenAll(task); 

      response = task.Result; 
     } 
     catch (PayPalException ex) 
     { 
      response = new TokenResponse { access_token = "error", Error = ex }; 
     } 

     return response; 
    } 
+0

tôi nhận được AuthenticationException-WebException về SSL/TLS . – Kiquenet

2

Hy vọng mã sau giúp bất kỳ ai vẫn đang tìm kiếm một miếng bánh ngon để kết nối với PayPal.

Như nhiều người, tôi đã và đang đầu tư rất nhiều thời gian cố gắng để có được PayPal access token của tôi mà không thành công, cho đến khi tôi thấy như sau:

public class PayPalClient 
{ 
    public async Task RequestPayPalToken() 
    { 
     // Discussion about SSL secure channel 
     // http://stackoverflow.com/questions/32994464/could-not-create-ssl-tls-secure-channel-despite-setting-servercertificatevalida 
     ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; 
     ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; 

     try 
     { 
      // ClientId of your Paypal app API 
      string APIClientId = "**_[your_API_Client_Id]_**"; 

      // secret key of you Paypal app API 
      string APISecret = "**_[your_API_secret]_**"; 

      using (var client = new System.Net.Http.HttpClient()) 
      { 
       var byteArray = Encoding.UTF8.GetBytes(APIClientId + ":" + APISecret); 
       client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); 

       var url = new Uri("https://api.sandbox.paypal.com/v1/oauth2/token", UriKind.Absolute); 

       client.DefaultRequestHeaders.IfModifiedSince = DateTime.UtcNow; 

       var requestParams = new List<KeyValuePair<string, string>> 
          { 
           new KeyValuePair<string, string>("grant_type", "client_credentials") 
          }; 

       var content = new FormUrlEncodedContent(requestParams); 
       var webresponse = await client.PostAsync(url, content); 
       var jsonString = await webresponse.Content.ReadAsStringAsync(); 

       // response will deserialized using Jsonconver 
       var payPalTokenModel = JsonConvert.DeserializeObject<PayPalTokenModel>(jsonString); 
      } 
     } 
     catch (System.Exception ex) 
     { 
      //TODO: Log connection error 
     } 
    } 
} 

public class PayPalTokenModel 
{ 
    public string scope { get; set; } 
    public string nonce { get; set; } 
    public string access_token { get; set; } 
    public string token_type { get; set; } 
    public string app_id { get; set; } 
    public int expires_in { get; set; } 
} 

Mã này hoạt động khá tốt đối với tôi, với hy vọng cho bạn cũng vậy. Các khoản tín dụng thuộc về Patel Harshal, người đã đăng giải pháp của mình here.

+0

CẢM ƠN! Bạn đã tiết kiệm được một nửa trong ngày của tôi. –

1

Paypal không được chấp nhận TLS 1.1 và chỉ chấp nhận 1.2 ngay bây giờ. Thật không may .NET sử dụng 1.1 theo mặc định, trừ khi bạn cấu hình nó theo cách khác.

Bạn có thể bật TLS 1.2 bằng dòng này. Tôi khuyên bạn nên đặt nó Application_Start hoặc global.asax.

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 
0

Tôi cũng bị thiếu mã ví dụ và các vấn đề khác nhau với lỗi và mã phản hồi.

Tôi là người hâm mộ lớn của RestClient vì nó giúp ích rất nhiều với việc tích hợp và số lượng cuộc gọi API RESTful ngày càng tăng.

Tôi hy vọng đoạn nhỏ của mã sử dụng RestSharp giúp ai đó: -

 if (ServicePointManager.SecurityProtocol != SecurityProtocolType.Tls12) ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // forced to modern day SSL protocols 
     var client = new RestClient(payPalUrl) { Encoding = Encoding.UTF8 }; 
     var authRequest = new RestRequest("oauth2/token", Method.POST) {RequestFormat = DataFormat.Json}; 
     client.Authenticator = new HttpBasicAuthenticator(clientId, secret); 
     authRequest.AddParameter("grant_type","client_credentials"); 
     var authResponse = client.Execute(authRequest); 
     // You can now deserialise the response to get the token as per the answer from @ryuzaki 
     var payPalTokenModel = JsonConvert.DeserializeObject<PayPalTokenModel>(authResponse.Content); 
Các vấn đề liên quan