web-dev-qa-db-fra.com

Type de subvention non pris en charge C # lors de l'appel de l'API Web

J'essaie d'effectuer une publication sur mon WebAPI à partir d'une application de bureau c # WPF.

Peu importe ce que je fais, je reçois

{"error": "unsupported_grant_type"}

C'est ce que j'ai essayé (et j'ai essayé tout ce que j'ai pu trouver):

Également, une API Web dev actuellement active pour les tests: http://studiodev.biz/

objet client http de base:

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("*/*"));

avec les méthodes d'envoi suivantes:

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

Après cela a échoué, j'ai fait quelques recherches sur Google et essayé:

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

même résultat, alors j'ai essayé:

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

Remarque: je peux passer un appel avec succès avec Chrome.

Mise à jour du résultat Fiddler

enter image description here

Est-ce que quelqu'un pourrait m'aider à passer un appel réussi à l'API Web ci-dessus ... Merci de me faire savoir si je peux aider à clarifier. Merci!!

57
OverMars

L’implémentation par défaut de OAuthAuthorizationServerHandler n’accepte que le codage de formulaire (c.-à-d. application/x-www-form-urlencoded) et non JSON (application/JSON).

Votre demande ContentType devrait être application/x-www-form-urlencoded et transmettez les données dans le corps en tant que:

grant_type=password&username=Alice&password=password123

c'est-à-dire pas au format JSON .

L'exemple ci-dessus chrome) fonctionne car il ne transmet pas de données au format JSON. Vous en avez besoin uniquement pour obtenir un jeton; vous pouvez utiliser JSON pour les autres méthodes de votre API.

Ce genre de problème est également discuté ici .

131
M. Ali Iftikhar

1) Notez l'URL: "localhost: 55828/token" (pas "localhost: 55828/API/token")

2) Notez les données de la demande. Ce n'est pas au format JSON, c'est juste des données sans plis. "[email protected]&password=Test123$&grant_type=password"

3) Notez le type de contenu. Content-Type: 'application/x-www-formulaire-urlencoded' (pas Content-Type: 'application/json')

4) Lorsque vous utilisez javascript pour faire une demande de publication, vous pouvez utiliser ce qui suit:

$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) {//...

Voir les captures d'écran ci-dessous de Postman:

Postman Request

Postman Request Header

13
Chirag

Voici un exemple de travail que j'ai utilisé pour faire cette demande de mon application API Web locale s'exécutant sur le port 43305 à l'aide de SSL. J'ai aussi mis le projet sur 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; }

    }

  }
}
11
Casey Gregoire

Si vous utilisez RestSharp, vous devez faire la demande comme ceci:

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;

        }
7

Avait les mêmes problèmes, mais seulement résolu le mien sur HTTP sécurisé pour l'URL de jeton. Voir un exemple de code httpclient. HTTP ordinaire cesse de fonctionner après la maintenance du serveur

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;
0
Afis