J'ai suivi cet article pour implémenter un serveur d'autorisation OAuth. Cependant, lorsque j'utilise post man pour obtenir un jeton, je reçois une erreur dans la réponse:
"error": "unsupported_grant_type"
J'ai lu quelque part que les données dans Postman doivent être publiées avec Content-type:application/x-www-form-urlencoded
. J'ai préparé les paramètres requis dans Postman:
et pourtant mes en-têtes sont comme ceci:
Voici mon 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();
}
}
Dans la classe CustomJWTFormat ci-dessus, seul le point d'arrêt du constructeur est touché. Dans la classe CustomOauth, le point d'arrêt de la méthode GrantResourceOwnerCredentials n'est jamais touché. Les autres font.
La classe de démarrage:
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)
}
});
}
}
Dois-je configurer Content-type:application/x-www-form-urlencoded
ailleurs dans le code de l'API Web? Quel pourrait être le problème? S'il vous plaît aider.
La réponse est un peu tardive - mais au cas où quelqu'un aurait le problème à l'avenir ...
Dans la capture d'écran ci-dessus, il semble que vous ajoutiez les données de l'URL (nom d'utilisateur, mot de passe, grant_type) à l'en-tête et non à l'élément body.
En cliquant sur l'onglet du corps, puis en sélectionnant le bouton radio "x-www-form-urlencoded", il devrait y avoir une liste de valeurs-clés sous laquelle vous pouvez saisir les données de la demande.
Avec Postman, sélectionnez l'onglet Corps, choisissez l'option brute et entrez les informations suivantes:
grant_type=password&username=yourusername&password=yourpassword
localhost:55828/token
(pas localhost:55828/API/token
)[email protected]&password=Test123$&grant_type=password
Lorsque vous utilisez JavaScript pour faire une demande de publication, vous pouvez utiliser les éléments suivants:
$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:
Si vous utilisez AngularJS, vous devez transmettre les paramètres du corps sous forme de chaîne:
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' }
});
};
essayez d'ajouter ceci dans votre charge utile
grant_type=password&username=pippo&password=pluto
Ancienne question, mais pour angular 6
, vous devez le faire lorsque vous utilisez HttpClient
J'expose publiquement les données de jetons ici, mais ce serait bien si vous y accédez via des propriétés en lecture seule.
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;
}
)
);
}
}
Je recevais aussi cette erreur et la raison en était un mauvais appel url. Je laisse cette réponse ici, si quelqu'un d'autre mélange les URL et obtient cette erreur. Il m'a fallu des heures pour comprendre que j'avais une mauvaise URL.
Erreur que j'ai eu (code HTTP 400):
{
"error": "unsupported_grant_type",
"error_description": "grant type not supported"
}
J'appelais:
https://MY_INSTANCE.lightning.force.com
Alors que l'URL correcte aurait été: