2013-06-02 15 views
6

Sto provando a chiamare Paypal api dal mio codice. Ho configurato l'account sandbox e funziona quando uso curl, ma il mio codice non funziona allo stesso modo, restituendo invece 401 Non autorizzato.Paypal REST la chiamata api funziona da cURL ma non dal codice C#

Ecco il comando di arricciatura come 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: A quanto pare il .Credentials non fa il trucco, invece impostazione Authorization intestazione lavora manualmente (vedi codice)

Ecco il codice (rifilato alla sua essenza):

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

Questa è la richiesta f Codice rom catturato da Fiddler (grezzo), non ci sono parametri di autorizzazione per qualche motivo:

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'è uno spazio mancante nell'intestazione accettare, ma non riesco a vedere qualsiasi altra cosa ovvia. Hai provato a catturare le due richieste per vedere cosa è diverso, ad es. usando wireshark o un proxy come Fiddler? – Rup

+0

@Rup Ho provato con Fiddler, avendo ancora problemi a catturare la richiesta di arricciatura ma la richiesta di codice non contiene le intestazioni Auth (vedi aggiornamento) –

+1

Sì alcune librerie HTTP, ad es. Apache non invierà le credenziali a meno che non le venga richiesto dal server remoto, ma non sapevo che anche .NET lo fosse. O almeno dovrebbe rispondere al 401 con loro. Potrebbe esserci un modo per forzarlo anche sull'oggetto richiesta? – Rup

risposta

3

Questo funziona utilizzando HttpClient ... 'RequestT' è un generico per gli argomenti di richiesta di PayPal, tuttavia non viene utilizzato . Viene utilizzato "ResponseT" ed è la risposta di PayPal in base alla relativa documentazione.

La classe 'PayPalConfig' legge il clientid e il segreto dal file web.config utilizzando ConfigurationManager. La cosa da ricordare è impostare l'intestazione Autorizzazione su "Base" NOT "Bearer" e se e per costruire correttamente l'oggetto "StringContent" con il tipo di supporto corretto (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; 
    } 

IMPORTANTE: utilizzare Task.WhenAll() per assicurarsi di avere un risultato.

// 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

Ricevo AuthenticationException-WebException su SSL/TLS . – Kiquenet

2

Sperando che il seguente codice di aiuto a chi è ancora alla ricerca di una buona fetta di torta per essere collegati a PayPal.

Come molte persone, ho investito un sacco di tempo a cercare di ottenere il mio PayPal token di accesso senza successo, fino a quando ho trovato il seguente:

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

Questo codice funziona abbastanza bene per me, sperando in anche tu. I crediti appartengono a Patel Harshal che ha pubblicato la sua soluzione here.

+0

GRAZIE! Hai salvato metà della mia giornata. –

1

Paypal come deprecato TLS 1.1 e accetta solo 1,2 ora. Sfortunatamente .NET usa 1.1 di default, a meno che non lo si configuri diversamente.

È possibile attivare TLS 1.2 con questa linea. Raccomando di posizionarlo Application_Start o global.asax.

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 
0

Anch'io ho sofferto di mancanza di codice di esempio e di vari problemi con errori di risposta e codici.

Sono un grande fan di RestClient in quanto aiuta molto con le integrazioni e il numero crescente di chiamate API RESTful.

Spero che questo piccolo frammento di codice usando RestSharp aiuta qualcuno: -

 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); 
Problemi correlati