2015-03-31 29 views
36

Podążałem za this article, aby zaimplementować serwer autoryzacji OAuth. Jednak kiedy używam pocztowy człowieka, aby uzyskać znak, pojawia się błąd w odpowiedzi:Uzyskiwanie "błędu": "unsupported_grant_type" podczas próby uzyskania JWT przez wywołanie OWIN OAuth zabezpieczonego Web Api za pośrednictwem Postmana

„błąd”: „unsupported_grant_type”

Czytałem gdzieś, że dane w Listonosz musi być wysłana przy użyciu Content-type:application/x-www-form-urlencoded. Mam dobrze przygotowane wymagane ustawienia w Listonosz:

enter image description here

i jeszcze moje nagłówki są tak:

enter image description here

Oto mój kod

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

W klasie CustomJWTFormat powyżej uderza tylko punkt przerwania w konstruktorze. W klasie CustomOauth punkt przerwania w metodzie GrantResourceOwnerCredentials nigdy nie zostanie trafiony. Inni robią.

Klasa Uruchomienie:

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

Czy muszę założyć Content-type:application/x-www-form-urlencoded gdzieś w kodzie Web API? Co może być nie tak? Proszę pomóż.

+0

Nie chcę podawać hasła użytkownika raczej, chcę je zweryfikować za pomocą zewnętrznych dostawców, takich jak klucz konsumenta twitter i tajny klucz klienta, jak mogę to zrobić? – Neo

+0

Dzięki za to, chociaż twoje pytanie i ostateczna odpowiedź nie były tym, czego szukałem, wydaje mi się, że wstawiony fragment rozwiązał to za mnie. Zmagałem się z punktem tokenu OPCJE OPCJE chronionym przez identyfikator/sekret klienta. Uratowałeś mnie! –

Odpowiedz

65

Odpowiedź jest nieco późno - ale w przypadku gdy ktoś ma problem w przyszłości ...

Z powyższym zrzucie ekranu - wydaje się, że dodajesz dane URL (nazwa użytkownika, hasło) do grant_type nagłówek, a nie element ciała.

Kliknięcie na zakładce ciała, a następnie wybierz „x-www-form-urlencoded” przycisk radiowy, nie powinno być lista klucz-wartość poniżej której można wprowadzić dane żądania

+1

W jaki sposób mogę wykonać to samo żądanie z granicznego połączenia serwisowego? –

1

Spróbuj dodać ten w swojej ładowności

grant_type=password&username=pippo&password=pluto 
26

z Postman, wybierz zakładkę Ciało i wybrać opcję surowego i wpisz następujące polecenie:

grant_type=password&username=yourusername&password=yourpassword 
+1

To działało ładnie dla mnie, dzięki! – CodeOrElse

+0

dla organów, które zawierają znaki specjalne, takie jak 'p @ ssword', musisz zastąpić" @ ""% 40 "? –

+0

Pracował dla mnie cudownie. Wielkie dzięki. – Nagesh

11
  1. Zanotuj adres URL: localhost:55828/token (nie localhost:55828/API/token)
  2. Zwróć uwagę na dane żądania. Nie ma go w formacie json, to zwykłe dane bez podwójnych cytatów. [email protected]&password=Test123$&grant_type=password
  3. Uwaga na typ zawartości.Content-Type: 'application/x-www-form-urlencoded' (nie Content-Type: 'application/json')
  4. Podczas korzystania JavaScript, aby żądania POST, można użyć następujących:

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

zobacz zdjęcia poniżej z Postman:

Postman Request

Postman Request Header

+1

Wysyłam tę samą prośbę, jak opisano powyżej, nadal otrzymuję invalid_grant. Proszę zaproponować rozwiązanie. – sadhana

+0

Świetna odpowiedź! Kroki pomogły. – OverMars

-2

Użyj: grant_type = {Twoje hasło} enter image description here