C# 使用 Nest API Restful 使用 HttpClient 进行身份验证

C# Works with Nest API Restful Auth using HttpClient

我还是 C# 的新手,我确信我没有正确使用 HttpClient 库。我正在尝试使用 Works With Nest API 进行身份验证,以便我可以 read/write 向恒温器发出请求。下面是我用来验证的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using System.Net.Http;
using System.Net.Http.Headers;


namespace iConnect.Controllers
{
    public class NestController : Controller
    {
        static HttpClient client = new HttpClient();

        public IActionResult Index()
        {
            return View();
        }

        public async Task<HttpResponseMessage> GetNestAuthCode()
        {
            // Nest Pin Code
            String pincode = "MYPING";
            String clientID = "My-Client-ID";
            String clientSecret = "MySecretString";
            String grantType = "authorization_code";

            client.BaseAddress = new Uri("https://api.home.nest.com");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            var request = new HttpRequestMessage(HttpMethod.Post, "/oauth2/access_token");

            var data = new List<KeyValuePair<string, string>>
            {                
                new KeyValuePair<string, string>("code", pincode)
                , new KeyValuePair<string, string>("client_id", clientID)
                , new KeyValuePair<string, string>("client_secret", clientSecret)
                , new KeyValuePair<string, string>("grant_type", grantType)
            };

            //var content = new FormUrlEncodedContent(data);
            //await content.ReadAsByteArrayAsync();
            //content.Add(data);
            request.Content = new FormUrlEncodedContent(data);

            //HttpResponseMessage response = await client.PostAsync(client.BaseAddress, content);

            HttpResponseMessage response = await client.SendAsync(request);

            return response;
        }
    }
}

当我转到 localhost:9387/Nest/GetAuthCode 时,我得到以下 JSON 响应:

{
   "version":{
      "major":1,
      "minor":1,
      "build":-1,
      "revision":-1,
      "majorRevision":-1,
      "minorRevision":-1
   },
   "content":{
      "headers":[
         {
            "key":"Content-Type",
            "value":[
               "application/json"
            ]
         }
      ]
   },
   "statusCode":400,
   "reasonPhrase":"Bad Request",
   "headers":[
      {
         "key":"Connection",
         "value":[
            "keep-alive"
         ]
      }
   ],
   "requestMessage":{
      "version":{
         "major":1,
         "minor":1,
         "build":-1,
         "revision":-1,
         "majorRevision":-1,
         "minorRevision":-1
      },
      "content":{
         "headers":[
            {
               "key":"Content-Type",
               "value":[
                  "application/x-www-form-urlencoded"
               ]
            },
            {
               "key":"Content-Length",
               "value":[
                  "130"
               ]
            }
         ]
      },
      "method":{
         "method":"POST"
      },
      "requestUri":"https://api.home.nest.com/oauth2/access_token",
      "headers":[
         {
            "key":"Accept",
            "value":[
               "application/json"
            ]
         }
      ],
      "properties":{

      }
   },
   "isSuccessStatusCode":false
}

非常感谢任何帮助。谢谢。

编辑:

我进行了以下更改并得到以下响应(这不是我所期望的):

代码:

public async Task<ActionResult> GetNestAuthCode()
        {
            // Nest Pin Code
            String pincode = "MYPING";
            String clientID = "My-Client-ID";
            String clientSecret = "MySecretString";
            String grantType = "authorization_code";

            client.BaseAddress = new Uri("https://api.home.nest.com");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            //var request = new HttpRequestMessage(HttpMethod.Post, "/oauth2/access_token");

            var data = new List<KeyValuePair<string, string>>
            {                
                new KeyValuePair<string, string>("code", pincode)
                , new KeyValuePair<string, string>("client_id", clientID)
                , new KeyValuePair<string, string>("client_secret", clientSecret)
                , new KeyValuePair<string, string>("grant_type", grantType)
            };

            //var content = new FormUrlEncodedContent(data);
            //await content.ReadAsByteArrayAsync();
            //content.Add(data);
            //request.Content = new FormUrlEncodedContent(data);

            //HttpResponseMessage response = await client.PostAsync(client.BaseAddress, content);

            var response = await client.PostAsync("oauth2/access_token",
                    new FormUrlEncodedContent(data));

            var content = await response.Content.ReadAsStringAsync();

            return Content(content);
        }

回复:

{"error":"oauth2_error","error_description":"authorization code not found","instance_id":"f64d5268-8bec-4799-927c-e53454ed96d5"}

您正在 return 您正在从您的操作方法返回完整的响应消息,包括它的所有属性和值。相反,您应该只阅读其内容和 return。如果您愿意,可以找到一篇关于使用内置 .NET HttpClienthere 的好文章。

我会做的是:

public async Task<IActionResult> GetNestAuthCode()
{
    // HttpClient setup...

    var content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("code", "MYPING"),
        new KeyValuePair<string, string>("client_id", "My-Client-ID"),
        new KeyValuePair<string, string>("client_secret", "MySecretString"),
        new KeyValuePair<string, string>("grant_type", "authorization_code")
    });

    var response = await client.PostAsync("oauth2/access_token", content);

    // Or check instead with IsSuccessStatusCode
    response.EnsureSuccessStatusCode();

    // ReadAsStringAsync() is just an example here
    var responseContent = await response.Content.ReadAsStringAsync();

    return Content(responseContent);
}

请注意...

  • 我仍在使用 IActionResult(或者实际上是 Task<IActionResult>)作为 return 类型。 你不应该 return 响应对象。
  • 我是直接用PostAsync()方法,相关内容为FormUrlEncodedContent,而不是先建一个HttpRequestMessage再用SendAsync().
  • 另外不要忘记检查您的请求是否成功!否则,您可能会 return 从您的操作方法中获取错误消息。
  • 我只是以 ReadAsStringAsync()return Content() 为例。

请注意,您对 Nest API 的请求有问题,因为它 returns 400 Bad Request。您应该能够从内容中的错误消息中准确地得出什么。 ;)

编辑

我快速浏览了 Nest API,我认为您为 code 提供了错误的值。我认为您应该先调用另一个 API 方法来检索授权码,然后再将其交换为访问令牌(如 here 所示),而不是指定您的 PIN 码。