如何在角度 http 请求中实现 client_credentials 授权类型?
Posted
技术标签:
【中文标题】如何在角度 http 请求中实现 client_credentials 授权类型?【英文标题】:How to implement a client_credentials grant type in an angular http request? 【发布时间】:2017-04-24 18:48:59 【问题描述】:我创建了一个 OAUTH2 授权服务器,它使用客户端凭据进行身份验证,并负责发布 JWT 令牌。当我使用邮递员发出请求时,我按预期获得了 JWT 令牌,但是当我将请求放入 Angular 时,我收到错误消息:“unsupported_grant_type”。
授权服务器的相关代码如下:
Startup.cs
public void Configuration(IAppBuilder app)
// HTTP Configuration
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
ConfigureOAuth(app);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
private void ConfigureOAuth(IAppBuilder app)
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth2/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new CustomOAuthProvider(ActiveKernel),
AccessTokenFormat = new CustomJwtFormat("http://localhost:62790", ActiveKernel)
;
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
CustomOAuthProvider.cs
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
string clientId;
string clientSecret;
Guid clientIdGuid;
if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
context.TryGetFormCredentials(out clientId, out clientSecret);
if (null == context.ClientId || null == clientSecret || !Guid.TryParse(clientId, out clientIdGuid))
context.SetError("invalid_credentials", "A valid client_Id and client_Secret must be provided");
return Task.FromResult<object>(null);
// change to async
var client = _clientRepo.GetClient(clientIdGuid, clientSecret);
if (client == null)
context.SetError("invalid_credentials", "A valid client_Id and client_Secret must be provided");
return Task.FromResult<object>(null);
context.Validated();
return Task.FromResult<object>(0);
public override async Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
var allowedOrigin = "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] allowedOrigin );
Guid clientId;
Guid.TryParse(context.ClientId, out clientId);
var client = _clientRepo.GetByClientId(clientId);
if (client == null)
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
var identity = new ClaimsIdentity("JWT");
identity.AddClaim(new Claim("fakeClaim", client.someField.ToString()));
var props = new AuthenticationProperties(new Dictionary<string, string>
"audience", (context.ClientId == null) ? string.Empty : context.ClientId
);
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
当我在邮递员中使用授权类型 Oauth2 向 http://localhost:55555/oauth2/Token 发出请求时,我会返回一个有效的 JWT 令牌,我可以将其添加到我的请求中:
但是,当我尝试使用 Angular 获取访问令牌时,我收到一条错误消息,指示:“unsupported_grant_type”。我想要的grant_type 是client_credentials。我已经尝试了多种角度方法来让它工作但没有运气。这是 Angular 中的当前请求:
function getLoginToken()
var auth = btoa("89C30F1E-DEE3-4C67-8P2E-9C974R5A35EA:B9wXE8Vo+FEkm2AnqFZlS+KJiwYc+bSnarpq90lGyBo=");
var loginToken = $http(
url: 'http://localhost:55555/oauth2/Token',
method: "POST",
data:
grant_type: 'client_credentials'
,
withCredentials: true,
headers:
"Authorization": "Basic " + auth,
'Content-Type': 'application/x-www-form-urlencoded'
).then(function(data)
return data;
).catch(function (errorResponse)
throw errorResponse;
);
return loginToken;
;
我尝试将 'Content-Type': 'application/x-www-form-urlencoded' 添加到标头并将grant_type 添加到 URL,但结果是相同的。如果我使用邮递员在不使用授权功能的情况下发出请求;但是使用 Body 'x-www-form-urlencoded' 我会收到与 angular 中相同的错误消息。
在 Angular 和第二个邮递员示例中,我实际上在 ValidateClientAuthentication 方法中得到了正确的 client_id 和 client_secret 并且上下文得到了验证。
这是两个请求的提琴手图像:
来自 Angular 的请求中断:
工作邮递员要求:
关于这里可能出了什么问题以及我如何能够解决问题的任何建议?
提前致谢!
【问题讨论】:
【参考方案1】:为了更清楚,原始请求的最小值必须是:
内容类型:application/x-www-form-urlencoded
grant_type=password&username=USERNAME&password=PASSWORD
【讨论】:
【参考方案2】:我通过添加以下代码行解决了这个问题:
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8";
var payload = $.param( grant_type: 'client_credentials' );
grant_type 现在作为键出现,“client_credentials”是值。整个请求如下所示:
function getLoginToken()
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8";
var payload = $.param( grant_type: 'client_credentials' );
var auth = btoa("89C30F1E-DEE3-4C67-8P2E-9C974R5A35EA:B9wXE8Vo+FEkm2AnqFZlS+KJiwYc+bSnarpq90lGyBo=");
var loginToken = $http(
url: 'http://localhost:55555/oauth2/Token',
method: "POST",
data: payload,
withCredentials: true,
headers:
"Authorization": "Basic " + auth,
'Content-Type': 'application/x-www-form-urlencoded'
).then(function(data)
return data;
).catch(function (errorResponse)
throw errorResponse;
);
return loginToken;
;
我希望这可以帮助某人!
【讨论】:
让我问你为什么要为公共客户做这个流程? Angular 是公共客户端,在公共客户端场景中不应该使用客户端凭据。 不建议对 spa 应用使用客户端凭据授予类型。根据RFC 6749,它只能由机密客户使用。以上是关于如何在角度 http 请求中实现 client_credentials 授权类型?的主要内容,如果未能解决你的问题,请参考以下文章