Paypal REST API выкліку працуе з Curl, але не з C # код

Я спрабую патэлефанаваць Paypal АПА з майго кода. Я стварыў пясочніцы рахунак, і яна працуе, калі я выкарыстоўваю завітак, але мой код не працуе сапраўды гэтак жа, вяртаючыся 401 Несанкцыянаванае замест гэтага.

Here's the curl command as 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: Apparently the .Credentials doesn't do the trick, instead setting Authorization header manually works (see code)

Вось код (абразаецца па сваёй сутнасці):

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

Гэта запыт з кода, захопленага скрыпач (сырой), няма ніякіх параметраў аўтарызацыі для якой-небудзь прычыны:

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
6
@Rup Я паспрабаваў з Скрыпач, па-ранейшаму ўзнікаюць праблемы, захапляльную завітак запыт, але запыт кода не ўтрымлівае Auth загалоўкі (гл абнаўленне)
дададзена аўтар Sten Petrov, крыніца
@Rup Я паспрабаваў з Скрыпач, па-ранейшаму ўзнікаюць праблемы, захапляльную завітак запыт, але запыт кода не ўтрымлівае Auth загалоўкі (гл абнаўленне)
дададзена аўтар Sten Petrov, крыніца
@Rup Я паспрабаваў з Скрыпач, па-ранейшаму ўзнікаюць праблемы, захапляльную завітак запыт, але запыт кода не ўтрымлівае Auth загалоўкі (гл абнаўленне)
дададзена аўтар Sten Petrov, крыніца
@Rup да я выявіў, што і працаваў вакол гэтай праблемы. Дзякуй за гледзячы на ​​яго
дададзена аўтар Sten Petrov, крыніца
@Rup да я выявіў, што і працаваў вакол гэтай праблемы. Дзякуй за гледзячы на ​​яго
дададзена аўтар Sten Petrov, крыніца
@Rup да я выявіў, што і працаваў вакол гэтай праблемы. Дзякуй за гледзячы на ​​яго
дададзена аўтар Sten Petrov, крыніца
Там у адсутнасці месца ў загалоўку прымае, але я не магу бачыць нічога іншага відавочнага. Ці спрабавалі вы захапіўшы два запыту, каб убачыць, што па-іншаму, напрыклад, з дапамогай Wireshark або проксі-сервер, такі як Скрыпач?
дададзена аўтар Rup, крыніца
Там непрыемны абходны ў гэтым старым адказу : пабудаваць свой уласны асноўны загаловак аўтэнтыфікацыі. Ці я думаў HttpWebRequest.PreAuthenticate ,
дададзена аўтар Rup, крыніца
Там непрыемны абходны ў гэтым старым адказу : пабудаваць свой уласны асноўны загаловак аўтэнтыфікацыі. Ці я думаў HttpWebRequest.PreAuthenticate ,
дададзена аўтар Rup, крыніца
Ды некаторыя HTTP бібліятэкі, напрыклад, Apache не будзе пасылаць ўліковыя дадзеныя, калі няма для іх на выдалены сервер, але я не ведаю, .NET-х таксама. Ці, па меншай меры, ён павінен затым адказаць на 401 з імі. Там можа быць шлях, каб прымусіць яго таксама на аб'екце запыту?
дададзена аўтар Rup, крыніца
Ды некаторыя HTTP бібліятэкі, напрыклад, Apache не будзе пасылаць ўліковыя дадзеныя, калі няма для іх на выдалены сервер, але я не ведаю, .NET-х таксама. Ці, па меншай меры, ён павінен затым адказаць на 401 з імі. Там можа быць шлях, каб прымусіць яго таксама на аб'екце запыту?
дададзена аўтар Rup, крыніца
Ды некаторыя HTTP бібліятэкі, напрыклад, Apache не будзе пасылаць ўліковыя дадзеныя, калі няма для іх на выдалены сервер, але я не ведаю, .NET-х таксама. Ці, па меншай меры, ён павінен затым адказаць на 401 з імі. Там можа быць шлях, каб прымусіць яго таксама на аб'екце запыту?
дададзена аўтар Rup, крыніца
Там у адсутнасці месца ў загалоўку прымае, але я не магу бачыць нічога іншага відавочнага. Ці спрабавалі вы захапіўшы два запыту, каб убачыць, што па-іншаму, напрыклад, з дапамогай Wireshark або проксі-сервер, такі як Скрыпач?
дададзена аўтар Rup, крыніца
Там у адсутнасці месца ў загалоўку прымае, але я не магу бачыць нічога іншага відавочнага. Ці спрабавалі вы захапіўшы два запыту, каб убачыць, што па-іншаму, напрыклад, з дапамогай Wireshark або проксі-сервер, такі як Скрыпач?
дададзена аўтар Rup, крыніца
магчыма дублікат Прымус Basic Authentication ў WebRequest
дададзена аўтар Chris Pitman, крыніца
магчыма дублікат Прымус Basic Authentication ў WebRequest
дададзена аўтар Chris Pitman, крыніца
магчыма дублікат Прымус Basic Authentication ў WebRequest
дададзена аўтар Chris Pitman, крыніца
магчыма дублікат Прымус Basic Authentication ў WebRequest
дададзена аўтар Chris Pitman, крыніца

9 адказы

Спадзеючыся наступны код дапамогу для тых, хто ўсё яшчэ шукае добры кавалак пірага, каб падключыцца да PayPal.

Як і многія людзі, я інвеставаць шмат часу, спрабуючы атрымаць свой маркер доступу PayPal без поспеху, пакуль я не знайшоў наступнае:

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>
                            {
                                new KeyValuePair("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(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; }
}

Гэты код працуе вельмі добра для мяне, спадзеючыся, што для вас таксама. Крэдыты належаць Patel Harshal, які размясціў сваё рашэнне

4
дададзена
ДЗЯКУЙ! Вы выратавалі палову майго дня.
дададзена аўтар Max Favilli, крыніца

Paypal мае састарэлы TLS 1.1, і прымае толькі 1.2 цяпер. На жаль, .NET (да версіі 4.7) выкарыстоўвае 1.1 па змаўчанні, калі не наладжана інакш.

Вы можаце ўключыць TLS 1.2 з гэтай лініяй. Я рэкамендую змясціць яго Application_Start або global.asax .

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
3
дададзена

Paypal мае састарэлы TLS 1.1, і прымае толькі 1.2 цяпер. На жаль, .NET (да версіі 4.7) выкарыстоўвае 1.1 па змаўчанні, калі не наладжана інакш.

Вы можаце ўключыць TLS 1.2 з гэтай лініяй. Я рэкамендую змясціць яго Application_Start або global.asax .

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
3
дададзена

Paypal мае састарэлы TLS 1.1, і прымае толькі 1.2 цяпер. На жаль, .NET (да версіі 4.7) выкарыстоўвае 1.1 па змаўчанні, калі не наладжана інакш.

Вы можаце ўключыць TLS 1.2 з гэтай лініяй. Я рэкамендую змясціць яго Application_Start або global.asax .

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
3
дададзена

Гэта працуе з выкарыстаннем HttpClient ... «RequestT» з'яўляецца агульным для аргументаў запыту PayPal, аднак ён не выкарыстоўваецца. «ResponseT» выкарыстоўваецца, і гэта адказ ад PayPal у адпаведнасці з іх дакументацыяй.

Клас «» PayPalConfig чытае ClientID і сакрэт з файла web.config з дапамогай ConfigurationManager. Справа ў тым, каб памятаць, каб усталяваць Authorization загаловак «Basic» НЕ «аднанакіраванага», а калі і правільна пабудаваць аб'ект «StringContent» з правам тыпу носьбіта (х-WWW-формаў-urlencoded).

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

       //'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(error);
                throw new PayPalException { error_name = errResp.name, details = errResp.details, message = errResp.message };
            }

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

        return result;
    }

ВАЖНА: выкарыстоўвайце Task.WhenAll (), каб забяспечыць вам вынік.

   //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 AuthorizeAsync(TokenRequest req)
    {
        TokenResponse response;
        try
        {
            var task = new PayPalHttpClient().InvokePostAsync(req, req.actionUrl);
            await Task.WhenAll(task);

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

        return response;
    }
3
дададзена
Я атрымліваю AuthenticationException-WebException аб SSL/TLS.
дададзена аўтар Kiquenet, крыніца

Гэта працуе з выкарыстаннем HttpClient ... «RequestT» з'яўляецца агульным для аргументаў запыту PayPal, аднак ён не выкарыстоўваецца. «ResponseT» выкарыстоўваецца, і гэта адказ ад PayPal у адпаведнасці з іх дакументацыяй.

Клас «» PayPalConfig чытае ClientID і сакрэт з файла web.config з дапамогай ConfigurationManager. Справа ў тым, каб памятаць, каб усталяваць Authorization загаловак «Basic» НЕ «аднанакіраванага», а калі і правільна пабудаваць аб'ект «StringContent» з правам тыпу носьбіта (х-WWW-формаў-urlencoded).

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

       //'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(error);
                throw new PayPalException { error_name = errResp.name, details = errResp.details, message = errResp.message };
            }

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

        return result;
    }

ВАЖНА: выкарыстоўвайце Task.WhenAll (), каб забяспечыць вам вынік.

   //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 AuthorizeAsync(TokenRequest req)
    {
        TokenResponse response;
        try
        {
            var task = new PayPalHttpClient().InvokePostAsync(req, req.actionUrl);
            await Task.WhenAll(task);

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

        return response;
    }
3
дададзена
Я атрымліваю AuthenticationException-WebException аб SSL/TLS.
дададзена аўтар Kiquenet, крыніца

Гэта працуе з выкарыстаннем HttpClient ... «RequestT» з'яўляецца агульным для аргументаў запыту PayPal, аднак ён не выкарыстоўваецца. «ResponseT» выкарыстоўваецца, і гэта адказ ад PayPal у адпаведнасці з іх дакументацыяй.

Клас «» PayPalConfig чытае ClientID і сакрэт з файла web.config з дапамогай ConfigurationManager. Справа ў тым, каб памятаць, каб усталяваць Authorization загаловак «Basic» НЕ «аднанакіраванага», а калі і правільна пабудаваць аб'ект «StringContent» з правам тыпу носьбіта (х-WWW-формаў-urlencoded).

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

       //'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(error);
                throw new PayPalException { error_name = errResp.name, details = errResp.details, message = errResp.message };
            }

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

        return result;
    }

ВАЖНА: выкарыстоўвайце Task.WhenAll (), каб забяспечыць вам вынік.

   //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 AuthorizeAsync(TokenRequest req)
    {
        TokenResponse response;
        try
        {
            var task = new PayPalHttpClient().InvokePostAsync(req, req.actionUrl);
            await Task.WhenAll(task);

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

        return response;
    }
3
дададзена
Я атрымліваю AuthenticationException-WebException аб SSL/TLS.
дададзена аўтар Kiquenet, крыніца

Я таксама пакутаваў ад недахопу прыкладаў кода і розных праблем з памылкамі ў адказах і кодаў.

Я вялікі прыхільнік RestClient, паколькі гэта дапамагае шмат з інтэграцыяй і расце колькасцю выклікаў RESTful API.

Я спадзяюся, што гэты невялікі фрагмент кода з дапамогай RestSharp дапаможа каму-то: -

        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(authResponse.Content);
0
дададзена

Я таксама пакутаваў ад недахопу прыкладаў кода і розных праблем з памылкамі ў адказах і кодаў.

Я вялікі прыхільнік RestClient, паколькі гэта дапамагае шмат з інтэграцыяй і расце колькасцю выклікаў RESTful API.

Я спадзяюся, што гэты невялікі фрагмент кода з дапамогай RestSharp дапаможа каму-то: -

        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(authResponse.Content);
0
дададзена