webentwicklung-frage-antwort-db.com.de

"Error" erhalten: "unsupported_grant_type" beim Versuch, eine JWT abzurufen, indem eine OWIN OAuth-gesicherte Web-API über Postman aufgerufen wird

Ich habe diesem Artikel gefolgt, um einen OAuth-Autorisierungsserver zu implementieren. Wenn ich jedoch postman benutze, um ein Token zu erhalten, erhalte ich eine Fehlermeldung in der Antwort:

"error": "unsupported_grant_type"

Ich habe irgendwo gelesen, dass die Daten in Postman mit Content-type:application/x-www-form-urlencoded gepostet werden müssen. Ich habe die erforderlichen Einstellungen in Postman vorbereitet:

enter image description here

und doch sind meine Header so:

enter image description here

Hier ist mein Code

public class CustomOAuthProvider : OAuthAuthorizationServerProvider
{
    public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        context.Validated();
        return Task.FromResult<object>(null);
    }

    public override Task MatchEndpoint(OAuthMatchEndpointContext context)
    {
        if (context.OwinContext.Request.Method == "OPTIONS" && context.IsTokenEndpoint)
        {
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "POST" });
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "accept", "authorization", "content-type" });
            context.OwinContext.Response.StatusCode = 200;
            context.RequestCompleted();
            return Task.FromResult<object>(null);
        }
        return base.MatchEndpoint(context);       
    }

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        string allowedOrigin = "*";

        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Content-Type" });

        Models.TheUser user = new Models.TheUser();
        user.UserName = context.UserName;
        user.FirstName = "Sample first name";
        user.LastName = "Dummy Last name";

        ClaimsIdentity identity = new ClaimsIdentity("JWT");

        identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
        foreach (string claim in user.Claims)
        {
            identity.AddClaim(new Claim("Claim", claim));    
        }

        var ticket = new AuthenticationTicket(identity, null);
        context.Validated(ticket);
    }
}

public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
    private readonly string _issuer = string.Empty;

    public CustomJwtFormat(string issuer)
    {
        _issuer = issuer;
    }

    public string Protect(AuthenticationTicket data)
    {
        string audienceId = ConfigurationManager.AppSettings["AudienceId"];
        string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["AudienceSecret"];
        var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
        var signingKey = new HmacSigningCredentials(keyByteArray);
        var issued = data.Properties.IssuedUtc;
        var expires = data.Properties.ExpiresUtc;
        var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
        var handler = new JwtSecurityTokenHandler();
        var jwt = handler.WriteToken(token);
        return jwt;
    }

    public AuthenticationTicket Unprotect(string protectedText)
    {
        throw new NotImplementedException();
    }
}

In der obigen CustomJWTFormat-Klasse wird nur der Haltepunkt im Konstruktor getroffen. In der CustomOauth-Klasse wird der Haltepunkt in der GrantResourceOwnerCredentials-Methode nie getroffen. Die anderen tun es. 

Die Startup-Klasse:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

        HttpConfiguration config = new HttpConfiguration();
        WebApiConfig.Register(config);

        ConfigureOAuthTokenGeneration(app);
        ConfigureOAuthTokenConsumption(app);

        app.UseWebApi(config);
    }

    private void ConfigureOAuthTokenGeneration(IAppBuilder app)
    {
        var OAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            //For Dev enviroment only (on production should be AllowInsecureHttp = false)
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/oauth/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new CustomOAuthProvider(),
            AccessTokenFormat = new CustomJwtFormat(ConfigurationManager.AppSettings["Issuer"])
        };

        // OAuth 2.0 Bearer Access Token Generation
        app.UseOAuthAuthorizationServer(OAuthServerOptions);
    }

    private void ConfigureOAuthTokenConsumption(IAppBuilder app)
    {
        string issuer = ConfigurationManager.AppSettings["Issuer"]; 
        string audienceId = ConfigurationManager.AppSettings["AudienceId"];
        byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["AudienceSecret"]);

        // Api controllers with an [Authorize] attribute will be validated with JWT
        app.UseJwtBearerAuthentication(
            new JwtBearerAuthenticationOptions
            {
                AuthenticationMode = AuthenticationMode.Active,
                AllowedAudiences = new[] { audienceId },
                IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
                {
                    new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
                }
            });
    }
}

Muss ich Content-type:application/x-www-form-urlencoded an anderer Stelle im Web-API-Code einrichten? Was könnte falsch sein? Bitte helfen.

57
user20358

Die Antwort ist etwas spät - aber für den Fall, dass jemand das Problem in der Zukunft hat ...

Aus dem Screenshot oben - es scheint, dass Sie die URL-Daten (Benutzername, Kennwort, grant_type) zum Header hinzufügen und nicht zum body-Element.

Wenn Sie auf die Registerkarte "Körper" klicken und dann das Optionsfeld "x-www-form-urlencoded" auswählen, sollte sich darunter eine Liste mit Schlüsselwerten befinden, in die Sie die Anfragedaten eingeben können

103
MarkP

Wählen Sie mit Postman die Registerkarte Körper aus, wählen Sie die Option roh aus, und geben Sie Folgendes ein:

grant_type=password&username=yourusername&password=yourpassword
46
fojeeck
  1. Beachten Sie die URL: localhost:55828/token (nicht localhost:55828/API/token)
  2. Beachten Sie die Anforderungsdaten. Es ist nicht im Json-Format, es sind nur einfache Daten ohne Anführungszeichen .[email protected]&password=Test123$&grant_type=password
  3. Beachten Sie den Inhaltstyp. Content-Type: 'application/x-www-form-urlencoded' (nicht Content-Type: 'application/json')
  4. Wenn Sie JavaScript für eine Post-Anfrage verwenden, können Sie Folgendes verwenden:

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

Siehe untenstehende Screenshots von Postman:

 Postman Request

 Postman Request Header

16
Chirag

Wenn Sie AngularJS verwenden, müssen Sie die Body-Parameter als String übergeben:

    factory.getToken = function(person_username) {
    console.log('Getting DI Token');
    var url = diUrl + "/token";

    return $http({
        method: 'POST',
        url: url,
        data: 'grant_type=password&[email protected]&password=mypass',
        responseType:'json',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
    });
};
5
Gregory

versuchen Sie, dies in Ihre Nutzlast aufzunehmen

grant_type=password&username=pippo&password=pluto
2
Mauro Sala

Alte Frage, aber für angular 6 muss dies gemacht werden, wenn Sie HttpClient.__ verwenden. Ich mache hier Token-Daten öffentlich, aber es wäre gut, wenn Sie über schreibgeschützte Eigenschaften zugreifen.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { delay, tap } from 'rxjs/operators';
import { Router } from '@angular/router';


@Injectable()
export class AuthService {
    isLoggedIn: boolean = false;
    url = "token";

    tokenData = {};
    username = "";
    AccessToken = "";

    constructor(private http: HttpClient, private router: Router) { }

    login(username: string, password: string): Observable<object> {
        let model = "username=" + username + "&password=" + password + "&grant_type=" + "password";

        return this.http.post(this.url, model).pipe(
            tap(
                data => {
                    console.log('Log In succesful')
                    //console.log(response);
                    this.isLoggedIn = true;
                    this.tokenData = data;
                    this.username = data["username"];
                    this.AccessToken = data["access_token"];
                    console.log(this.tokenData);
                    return true;

                },
                error => {
                    console.log(error);
                    return false;

                }
            )
        );
    }
}
1

Ich habe auch diese Fehlermeldung erhalten und der Grund war eine falsche Aufruf-URL. Ich lasse diese Antwort hier, wenn jemand anderes die URLs mischt und diesen Fehler erhält. Es dauerte Stunden, bis mir klar wurde, dass ich eine falsche URL hatte.

Fehler, den ich bekam (HTTP-Code 400):

{
    "error": "unsupported_grant_type",
    "error_description": "grant type not supported"
}

Ich habe angerufen:

https://MY_INSTANCE.lightning.force.com

Die richtige URL wäre zwar gewesen:

https://MY_INSTANCE.cs110.my.salesforce.com

0
Firze