You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中从Duende Identity Server获取客户端令牌失败排查

问题:Angular调用Duende Identity Server获取客户端令牌返回400错误

项目背景

项目采用.NET API服务器、Duende Identity Server认证服务,前端为Angular应用。已实现登录用户可执行全部CRUD操作,未登录用户仅能执行读取操作。原方案在需登录访问的端点添加[Authorize]特性,但存在安全隐患——知晓端点URL的未登录用户仍可访问信息。计划改为未登录用户请求时携带客户端令牌,由API服务器校验后响应读取操作。

该逻辑已在Postman中验证通过,但Angular代码调用时持续返回400状态码(错误信息:invalid_request)。

现有Angular代码

getToken() {
    const headers = new HttpHeaders();
    headers.set('Authorization', `Basic client:secret`);
    headers.set("Content-Type", "application/json");
    const requestOptions = { headers: headers };
    let body = {
      "grant_type": "client_credentials",
      "client_id": "client",
      "client_secret": "secret",
      "scopes": "api",
      "response_type": "id_token token"
    }
    this.http.post("https://localhost:5001/connect/token", body, requestOptions).subscribe( result => {
       console.log(result);
     })
  }

API服务器CORS配置(Program.cs)

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAllHeaders",
        optionsBuilder =>
        {
            optionsBuilder.AllowAnyOrigin()
                .AllowAnyHeader()
                .AllowAnyMethod();
        });
});

IdentityServer请求日志

[08:50:01 Debug] Duende.IdentityServer.Hosting.CorsPolicyProvider
CORS request made for path: /.well-known/openid-configuration from origin: http://localhost:4200

[08:50:01 Debug] Duende.IdentityServer.Hosting.CorsPolicyProvider
CORS request made for path: /connect/token from origin: http://localhost:4200

[08:50:01 Debug] Duende.IdentityServer.Services.InMemoryCorsPolicyService
Client list checked and origin: http://localhost:4200 is allowed

[08:50:01 Debug] Duende.IdentityServer.Services.InMemoryCorsPolicyService
Client list checked and origin: http://localhost:4200 is allowed

[08:50:01 Debug] Duende.IdentityServer.Hosting.CorsPolicyProvider
CorsPolicyService allowed origin: http://localhost:4200

[08:50:01 Debug] Duende.IdentityServer.Hosting.CorsPolicyProvider
CorsPolicyService allowed origin: http://localhost:4200

[08:50:01 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: idsrv was not authenticated.

[08:50:01 Information] Serilog.AspNetCore.RequestLoggingMiddleware
HTTP OPTIONS /connect/token responded 204 in 14.3206 ms

[08:50:01 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: idsrv was not authenticated.

[08:50:01 Debug] Duende.IdentityServer.Hosting.EndpointRouter
Request path /.well-known/openid-configuration matched to endpoint type Discovery

[08:50:01 Debug] Duende.IdentityServer.Hosting.CorsPolicyProvider
CORS request made for path: /connect/token from origin: http://localhost:4200

[08:50:01 Debug] Duende.IdentityServer.Hosting.EndpointRouter
Endpoint enabled: Discovery, successfully created handler: Duende.IdentityServer.Endpoints.DiscoveryEndpoint

[08:50:01 Debug] Duende.IdentityServer.Services.InMemoryCorsPolicyService
Client list checked and origin: http://localhost:4200 is allowed

[08:50:01 Information] Duende.IdentityServer.Hosting.IdentityServerMiddleware
Invoking IdentityServer endpoint: Duende.IdentityServer.Endpoints.DiscoveryEndpoint for /.well-known/openid-configuration

[08:50:01 Debug] Duende.IdentityServer.Hosting.CorsPolicyProvider
CorsPolicyService allowed origin: http://localhost:4200

[08:50:01 Debug] Duende.IdentityServer.Endpoints.DiscoveryEndpoint
Start discovery request

[08:50:01 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: idsrv was not authenticated.

[08:50:01 Information] Duende.IdentityServer.Services.KeyManagement.KeyManager
Active signing key found with kid D576C7CF6598DABD3F65CBC5B29D6FD4 for alg RS256. Expires in 83.00:58:45. Retires in 97.00:58:45

[08:50:01 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: idsrv was not authenticated.

[08:50:01 Information] Serilog.AspNetCore.RequestLoggingMiddleware
HTTP GET /.well-known/openid-configuration responded 200 in 35.6220 ms

[08:50:01 Debug] Duende.IdentityServer.Hosting.EndpointRouter
Request path /connect/token matched to endpoint type Token

[08:50:01 Debug] Duende.IdentityServer.Hosting.EndpointRouter
Endpoint enabled: Token, successfully created handler: Duende.IdentityServer.Endpoints.TokenEndpoint

[08:50:01 Information] Duende.IdentityServer.Hosting.IdentityServerMiddleware
Invoking IdentityServer endpoint: Duende.IdentityServer.Endpoints.TokenEndpoint for /connect/token

[08:50:01 Warning] Duende.IdentityServer.Endpoints.TokenEndpoint
Invalid HTTP request for token endpoint

[08:50:01 Information] Serilog.AspNetCore.RequestLoggingMiddleware
HTTP POST /connect/token responded 400 in 39.8834 ms

问题排查与修复方案

Angular代码存在以下几个错误点:

1. HttpHeaders不可变,set方法未生效

HttpHeaders是不可变对象,调用set方法会返回新实例,原headers对象未被修改,导致设置的请求头未实际携带。

2. Basic认证凭证未Base64编码

HTTP Basic认证要求凭证(client:secret)必须经过Base64编码后放在Authorization头中,当前代码直接明文传递不符合规范。

3. 请求体格式与字段错误

Duende Identity Server的/connect/token端点要求客户端凭证模式的请求体采用application/x-www-form-urlencoded格式,而非application/json;同时请求体存在字段错误:

  • scopes应改为单数scope
  • response_type字段属于授权码/隐式流,客户端凭证模式不需要该字段

修复后的完整代码

getToken() {
  // 构建正确的请求头:Basic凭证编码 + 表单格式
  const authCredentials = btoa('client:secret');
  const headers = new HttpHeaders()
    .set('Authorization', `Basic ${authCredentials}`)
    .set('Content-Type', 'application/x-www-form-urlencoded');

  // 构建URL编码的请求体
  const body = new HttpParams()
    .set('grant_type', 'client_credentials')
    .set('client_id', 'client')
    .set('client_secret', 'secret')
    .set('scope', 'api');

  this.http.post("https://localhost:5001/connect/token", body, { headers })
    .subscribe(result => {
      console.log(result);
    }, error => {
      console.error('获取令牌失败:', error);
    });
}

额外验证点

  • 确认Duende Identity Server中客户端配置开启了client_credentials授权类型
  • 确认客户端的AllowedScopes包含api
  • 确保客户端的ClientSecrets配置与代码中一致

内容的提问来源于stack exchange,提问作者Filip C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 16:46:17