贝宝REST api调用工作从cURL,但不是从c#代码

本文关键字:代码 cURL REST api 调用 工作 贝宝 | 更新日期: 2023-09-27 18:16:49

我试图从我的代码调用Paypal api。我设置了沙箱帐户,当我使用curl时,它可以工作,但我的代码不以相同的方式工作,而是返回401未经授权。

这是Paypal文档中的curl命令

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:显然.Credentials没有做到这一点,而是手动设置Authorization头工作(见代码)

下面是代码:

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

这是Fiddler捕获的代码请求(原始),由于某种原因没有授权参数:

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

贝宝REST api调用工作从cURL,但不是从c#代码

希望下面的代码帮助任何人谁还在寻找一个很好的一块蛋糕得到连接到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<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; }
}

这段代码对我来说工作得很好,希望你也一样。感谢Patel Harshal在这里发布了他的解决方案。

这个工作使用HttpClient…'RequestT'是PayPal请求参数的通用参数,但它没有被使用。使用'ResponseT',根据他们的文档,它是PayPal的响应。

'PayPalConfig'类从web读取客户端和秘密。使用ConfigurationManager配置文件。要记住的是将授权头设置为"Basic"而不是"Bearer",并且正确构造具有正确媒体类型(x-www-form-urlencoded)的"StringContent"对象。

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

重要:使用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<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;
    }

Paypal已经弃用TLS 1.1,现在只接受1.2。不幸的是,. net(在版本4.7之前)默认使用1.1,除非您另行配置。

您可以使用这行打开TLS 1.2。我建议把它放在Application_Startglobal.asax

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

我也遭受了缺乏示例代码和响应错误和代码的各种问题。

我是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<PayPalTokenModel>(authResponse.Content);