【问题标题】:C# unsupported grant type when calling web api调用 web api 时 C# 不支持的授权类型
【发布时间】:2015-05-28 14:33:59
【问题描述】:

我正在尝试从 c# WPF 桌面应用程序向我的 WebAPI 执行发布。

无论我做什么,我都会得到

{"error":"unsupported_grant_type"}

这是我尝试过的(并且我已经尝试了我能找到的一切):

目前正在测试的还有开发 web api:http://studiodev.biz/

基础 http 客户端对象:

var client = new HttpClient()
client.BaseAddress = new Uri("http://studiodev.biz/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));

使用以下发送方法:

var response = await client.PostAsJsonAsync("token", "{'grant_type'='password'&'username'='username'&'password'='password'");
var response = await client.PostAsJsonAsync("token", "grant_type=password&username=username&password=password");

失败后,我做了一些谷歌搜索并尝试:

LoginModel data = new LoginModel(username, password);
string json = JsonConvert.SerializeObject(data);
await client.PostAsync("token", new JsonContent(json));

同样的结果,所以我尝试了:

req.Content = new StringContent(json, Encoding.UTF8, "application/x-www-form-urlencoded");
await client.SendAsync(req).ContinueWith(respTask =>
{
 Application.Current.Dispatcher.Invoke(new Action(() => { label.Content = respTask.Result.ToString(); }));
});

注意:我可以使用 Chrome 成功拨打电话。

更新 Fiddler 结果

有人可以帮我成功调用上面的 web api... 如果我能帮助澄清,请告诉我。 谢谢!!

【问题讨论】:

  • 您是否尝试过使用 Fiddler 来确定来自 Chrome 的调用与来自 WPF 应用程序的调用之间的区别?
  • 我有,请查看更新。我已经尝试了一切来复制结果。请帮忙。

标签: c# wpf asp.net-web-api httpclient token


【解决方案1】:

OAuthAuthorizationServerHandler 的默认实现只接受表单编码(即application/x-www-form-urlencoded)而不接受 JSON 编码(application/JSON)。

您的请求的 ContentType 应该是 application/x-www-form-urlencoded 并将正文中的数据传递为:

grant_type=password&username=Alice&password=password123

不是 JSON 格式

上面的 chrome 示例有效,因为它没有将数据作为 JSON 传递。你只需要这个来获取令牌;对于 API 的其他方法,您可以使用 JSON。

这种问题也讨论here

【讨论】:

  • 非常感谢!我被困了 3 天。
【解决方案2】:

1) 注意 URL:“localhost:55828/token”(不是“localhost:55828/API/token”)

2) 记下请求数据。它不是 json 格式,它只是没有双引号的纯数据。 "userName=xxx@gmail.com&password=Test123$&grant_type=password"

3) 注意内容类型。 Content-Type: 'application/x-www-form-urlencoded' (不是 Content-Type: 'application/json')

4) 当你使用javascript发出post请求时,你可以使用如下:

$http.post("localhost:55828/token", 
    "userName=" + encodeURIComponent(email) +
        "&password=" + encodeURIComponent(password) +
        "&grant_type=password",
    {headers: { 'Content-Type': 'application/x-www-form-urlencoded' }}
).success(function (data) {//...

请看下面 Postman 的截图:

【讨论】:

    【解决方案3】:

    这是一个工作示例,我使用 SSL 对在端口 43305 上运行的本地 Web API 应用程序发出此请求。我也把这个项目放在了 GitHub 上。 https://github.com/casmer/WebAPI-getauthtoken

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Newtonsoft.Json;
    using System.Net.Http;
    using System.Web;
    
    namespace GetAccessTokenSample
    {
      class Program
      {
        private static string baseUrl = "https://localhost:44305";
    
        static void Main(string[] args)
        {
    
          Console.WriteLine("Enter Username: ");
          string username= Console.ReadLine();
          Console.WriteLine("Enter Password: ");
          string password = Console.ReadLine();
    
          LoginTokenResult accessToken = GetLoginToken(username,password);
          if (accessToken.AccessToken != null)
          {
            Console.WriteLine(accessToken);
          }
          else
          {
            Console.WriteLine("Error Occurred:{0}, {1}", accessToken.Error, accessToken.ErrorDescription);
          }
    
        }
    
    
        private static LoginTokenResult GetLoginToken(string username, string password)
        {
    
          HttpClient client = new HttpClient();
          client.BaseAddress = new Uri(baseUrl);
          //TokenRequestViewModel tokenRequest = new TokenRequestViewModel() { 
          //password=userInfo.Password, username=userInfo.UserName};
          HttpResponseMessage response =
            client.PostAsync("Token",
              new StringContent(string.Format("grant_type=password&username={0}&password={1}",
                HttpUtility.UrlEncode(username),
                HttpUtility.UrlEncode(password)), Encoding.UTF8,
                "application/x-www-form-urlencoded")).Result;
    
          string resultJSON = response.Content.ReadAsStringAsync().Result;
          LoginTokenResult result = JsonConvert.DeserializeObject<LoginTokenResult>(resultJSON);
    
          return result;
        }
    
        public class LoginTokenResult
        {
          public override string ToString()
          {
            return AccessToken;
          }
    
          [JsonProperty(PropertyName = "access_token")]
          public string AccessToken { get; set; }
    
          [JsonProperty(PropertyName = "error")]
          public string Error { get; set; }
    
          [JsonProperty(PropertyName = "error_description")]
          public string ErrorDescription { get; set; }
    
        }
    
      }
    }
    

    【讨论】:

      【解决方案4】:

      如果您使用的是 RestSharp,则需要这样发出请求:

      public static U PostLogin<U>(string url, Authentication obj)
                  where U : new()
              {
                  RestClient client = new RestClient();
                  client.BaseUrl = new Uri(host + url);
                  var request = new RestRequest(Method.POST);
                  string encodedBody = string.Format("grant_type=password&username={0}&password={1}",
                      obj.username,obj.password);
                  request.AddParameter("application/x-www-form-urlencoded", encodedBody, ParameterType.RequestBody);
                  request.AddParameter("Content-Type", "application/x-www-form-urlencoded", ParameterType.HttpHeader);
                  var response = client.Execute<U>(request);
      
                   return response.Data;
      
              }
      

      【讨论】:

      • 这很有帮助,谢谢!对于那些希望稍后获得令牌的人,我只是复制了这个答案并在 client.Execute 调用之前添加了这一行:request.Resource = "Token";
      【解决方案5】:

      有同样的问题,但只通过安全 HTTP 为令牌 URL 解决了我的问题。请参阅示例 httpclient 代码。普通HTTP在服务器维护后就停止工作

      var apiUrl = "https://appdomain.com/token"
      var client = new HttpClient();    
      client.Timeout = new TimeSpan(1, 0, 0);
                  var loginData = new Dictionary<string, string>
                      {
                          {"UserName", model.UserName},
                          {"Password", model.Password},
                          {"grant_type", "password"}
                      };
                  var content = new FormUrlEncodedContent(loginData);
                  var response = client.PostAsync(apiUrl, content).Result;
      

      【讨论】:

      • 是服务器停止通过 http 接受请求吗?
      【解决方案6】:

      在我的情况下,我忘记安装安装包 Token.JWT,所以你也需要在你的项目中安装。 安装包 System.IdentityModel.Tokens.Jwt -Version 6.7.1

      【讨论】:

        【解决方案7】:

        可能是协议的原因 这是必需的 https://

        EX : https://localhost:port/oauth/token

        【讨论】:

          猜你喜欢
          • 2018-07-01
          • 1970-01-01
          • 2022-01-08
          • 1970-01-01
          • 2017-09-18
          • 1970-01-01
          • 2017-05-14
          • 1970-01-01
          相关资源
          最近更新 更多