具有个人帐户和 ASP.NET Core 托管的 Blazor WebAssembly 应用程序 - 令牌请求 - “错误”:“unauthorized_client”

2024-01-01

创建一个新的Blazor WebAssembly App with Microsoft Visual Studio 2019 Version 16.9.4具有这些规格:Target Framework .NET 5.0, Authentication Type Individual Accounts and ASP.NET Core Hosted:

提供一个包含这些的服务器项目NuGet版本5.0.5:

  • Microsoft.AspNetCore.ApiAuthorization.IdentityServer
  • Microsoft.AspNetCore.Identity.EntityFrameworkCore
  • Microsoft.AspNetCore.Identity.UI

Startup.cs 包含以下代码:

services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

services.AddAuthentication()
    .AddIdentityServerJwt();

阅读博客文章ASP.NET Core Authentication with IdentityServer4从 Microsoft 我应该能够通过示例请求检索令牌,如下所示:

POST /connect/token HTTP/1.1
Host: localhost:5000
Cache-Control: no-cache
Postman-Token: 958df72b-663c-5638-052a-aed41ba0dbd1
Content-Type: application/x-www-form-urlencoded

grant_type=password&username=Mike%40Contoso.com&password=MikesPassword1!&client_id=myClient&scope=myAPIs

https://devblogs.microsoft.com/aspnet/asp-net-core-authentication-with-identityserver4/ https://devblogs.microsoft.com/aspnet/asp-net-core-authentication-with-identityserver4/

创建一个看起来像这样的请求,但针对创建的解决方案:

POST /connect/token HTTP/1.1
Host: localhost:44388
Content-Type: application/x-www-form-urlencoded
Content-Length: 153

grant_type=password&username=example%40example.com&password=Password1&client_id=WebApplication4.Client&scope=WebApplication4.ServerAPI%20openid%20profile

此请求返回 HTTP 状态 400 错误请求,正文为:

{
    "error": "unauthorized_client"
}

我很确定这些值是正确的,因为我得到了client_id and scope来自用于登录 Web 应用程序的请求。该流量不使用grant_type=password尽管。登录请求示例:

https://localhost:44388/Identity/Account/Login?ReturnUrl=/connect/authorize/callback?client_id=WebApplication4.Client&redirect_uri=https%3A%2F%2Flocalhost%3A44388%2Fauthentication%2Flogin-callback&response_type=code&scope=WebApplication4.ServerAPI%20openid%20profile&state=12345&code_challenge=12345&code_challenge_method=S256&response_mode=query

确认用户存在并工作:

我缺少什么?


TLDR:

将其从appsettings.json:

"Clients": {
  "WebApplication4.Client": {
    "Profile": "IdentityServerSPA"
  }
}

Edit Startup.cs:

services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
    {
        options.Clients.AddIdentityServerSPA("WebApplication4.Client", builder =>
        {
            builder.WithRedirectUri("/authentication/login-callback");
            builder.WithLogoutRedirectUri("/authentication/logout-callback");
        });
        //Or Duende.IdentityServer.Models.Client
        options.Clients.Add(new IdentityServer4.Models.Client
        {
            ClientId = "WebApplication4.Integration",
            AllowedGrantTypes = { GrantType.ResourceOwnerPassword },
            //Use Configuration.GetSection("MySecretValue").Value; to get a value from appsettings.json
            ClientSecrets = { new Secret("MySecretValue".Sha256()) },
            AllowedScopes = { "WebApplication4.ServerAPI", "openid", "profile" }
        });
    });

该请求将起作用:

POST /connect/token HTTP/1.1
Host: localhost:44388
Content-Type: application/x-www-form-urlencoded
Content-Length: 168

grant_type=password&username=example%40example.com&password=Password1!&client_id=WebApplication4.Integration&scope=WebApplication4.ServerAPI&client_secret=MySecretValue

长答案:

我开始尝试通过日志记录获得更好的错误消息。

我将下面的代码添加到public static IHostBuilder CreateHostBuilder(string[] args) in Program.cs:

.ConfigureLogging(logging =>
{
    logging.ClearProviders();
    logging.AddConsole();
})

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-5.0 https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-5.0

调试时,我可以在发出请求时显示服务器应用程序的输出。它看起来像这样:

info: IdentityServer4.Hosting.IdentityServerMiddleware[0]
      Invoking IdentityServer endpoint: IdentityServer4.Endpoints.TokenEndpoint for /connect/token
info: IdentityServer4.Events.DefaultEventService[0]
      {
        "ClientId": "WebApplication4.Client",
        "AuthenticationMethod": "NoSecret",
        "Category": "Authentication",
        "Name": "Client Authentication Success",
        "EventType": "Success",
        "Id": 1010,
        "ActivityId": "8000000a-0000-8f00-b63f-84710c7967bb",
        "TimeStamp": "2021-04-29T11:47:07Z",
        "ProcessId": 8436,
        "LocalIpAddress": "::1:44388",
        "RemoteIpAddress": "::1"
      }
fail: IdentityServer4.Validation.TokenRequestValidator[0]
      Client not authorized for resource owner flow, check the AllowedGrantTypes setting{ client_id = WebApplication4.Client }, details: {
        "ClientId": "WebApplication4.Client",
        "ClientName": "WebApplication4.Client",
        "GrantType": "password",
        "Raw": {
          "grant_type": "password",
          "username": "[email protected] /cdn-cgi/l/email-protection",
          "password": "***REDACTED***",
          "client_id": "WebApplication4.Client",
          "scope": "WebApplication4.ServerAPI"
        }
      }
info: IdentityServer4.Events.DefaultEventService[0]
      {
        "ClientId": "WebApplication4.Client",
        "ClientName": "WebApplication4.Client",
        "Endpoint": "Token",
        "GrantType": "password",
        "Error": "unauthorized_client",
        "Category": "Token",
        "Name": "Token Issued Failure",
        "EventType": "Failure",
        "Id": 2001,
        "ActivityId": "8000000a-0000-8f00-b63f-84710c7967bb",
        "TimeStamp": "2021-04-29T11:47:07Z",
        "ProcessId": 8436,
        "LocalIpAddress": "::1:44388",
        "RemoteIpAddress": "::1"
      }

要查看的错误消息是Client not authorized for resource owner flow, check the AllowedGrantTypes setting{ client_id = WebApplication4.Client }.

有了这个错误消息,我发现了这个问题:

有关资源所有者密码授予类型的 ASP.NET Core 3 Identity/Identity Server/SPA 支持的问题 https://stackoverflow.com/questions/57899926/question-about-asp-net-core-3-identity-identity-server-spa-support-for-resou

在那里我可以阅读

发现在以下情况下未添加允许的密码授权类型 配置文件设置为 IdentityServerSPA。

看着appsettings.json该应用程序使用该配置文件:

"IdentityServer": {
  "Clients": {
    "WebApplication4.Client": {
      "Profile": "IdentityServerSPA"
    }
  }
},

看着Microsoft Application profiles它实际上做的是这样的:

  • redirect_uri 默认为 /authentication/login-callback。
  • post_logout_redirect_uri 默认为 /身份验证/注销回调。
  • 范围集包括 openid、profile 和 every 范围 为应用程序中的 API 定义。
  • 允许的 OIDC 响应类型集是 id_token 令牌或每个 它们分别(id_token、token)。
  • 允许的响应模式是片段。

https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity-api-authorization?view=aspnetcore-5.0#application-profiles https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity-api-authorization?view=aspnetcore-5.0#application-profiles

在开始修改之前,我访问了该 URLhttps://localhost:44388/.well-known/openid-configuration获取当前配置。它看起来像这样,并具体说grant_types_supported: ...password:

{
    "issuer": "https://localhost:44388",
    "jwks_uri": "https://localhost:44388/.well-known/openid-configuration/jwks",
    "authorization_endpoint": "https://localhost:44388/connect/authorize",
    "token_endpoint": "https://localhost:44388/connect/token",
    "userinfo_endpoint": "https://localhost:44388/connect/userinfo",
    "end_session_endpoint": "https://localhost:44388/connect/endsession",
    "check_session_iframe": "https://localhost:44388/connect/checksession",
    "revocation_endpoint": "https://localhost:44388/connect/revocation",
    "introspection_endpoint": "https://localhost:44388/connect/introspect",
    "device_authorization_endpoint": "https://localhost:44388/connect/deviceauthorization",
    "frontchannel_logout_supported": true,
    "frontchannel_logout_session_supported": true,
    "backchannel_logout_supported": true,
    "backchannel_logout_session_supported": true,
    "scopes_supported": [
        "openid",
        "profile",
        "WebApplication4.ServerAPI",
        "offline_access"
    ],
    "claims_supported": [
        "sub",
        "name",
        "family_name",
        "given_name",
        "middle_name",
        "nickname",
        "preferred_username",
        "profile",
        "picture",
        "website",
        "gender",
        "birthdate",
        "zoneinfo",
        "locale",
        "updated_at"
    ],
    "grant_types_supported": [
        "authorization_code",
        "client_credentials",
        "refresh_token",
        "implicit",
        "password",
        "urn:ietf:params:oauth:grant-type:device_code"
    ],
    "response_types_supported": [
        "code",
        "token",
        "id_token",
        "id_token token",
        "code id_token",
        "code token",
        "code id_token token"
    ],
    "response_modes_supported": [
        "form_post",
        "query",
        "fragment"
    ],
    "token_endpoint_auth_methods_supported": [
        "client_secret_basic",
        "client_secret_post"
    ],
    "id_token_signing_alg_values_supported": [
        "RS256"
    ],
    "subject_types_supported": [
        "public"
    ],
    "code_challenge_methods_supported": [
        "plain",
        "S256"
    ],
    "request_parameter_supported": true
}

因为某些原因IdentityServer Clients无法在代码和中进行配置appsettings.json。因此我删除了Clients from appsettings.json并将其添加到 Startup.cs 中:

services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
    {
        options.Clients.AddIdentityServerSPA("WebApplication4.Client", builder =>
        {
            builder.WithRedirectUri("/authentication/login-callback");
            builder.WithLogoutRedirectUri("/authentication/logout-callback");
        });
        options.Clients.Add(new IdentityServer4.Models.Client
        {
            ClientId = "WebApplication4.Integration",
            AllowedGrantTypes = { GrantType.ResourceOwnerPassword },
            AllowedScopes = { "WebApplication4.ServerAPI", "openid", "profile" }
        });
    });

Without WithRedirectUri and WithLogoutRedirectUri它不起作用,OidcConfigurationController有一个例外ClientRequestParametersProvider.GetClientParameters(HttpContext, clientId); with System.InvalidOperationException: 'Sequence contains no elements'。由于某种原因,使用时会自动修复此问题appsettings.json.

我现在在发布到时收到错误消息/connect/token:

{
    "error": "invalid_client"
}

但我在日志中得到了一个更好的错误:

Invalid client configuration for client WebApplication4.Integration: Client secret is required for password, but no client secret is configured.

添加了一个秘密Startup.cs:

services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
    {
        options.Clients.AddIdentityServerSPA("WebApplication4.Client", builder =>
        {
            builder.WithRedirectUri("/authentication/login-callback");
            builder.WithLogoutRedirectUri("/authentication/logout-callback");
        });
        options.Clients.Add(new IdentityServer4.Models.Client
        {
            ClientId = "WebApplication4.Integration",
            AllowedGrantTypes = { GrantType.ResourceOwnerPassword },
            //Use Configuration.GetSection("MySecretValue").Value; to get a value from appsettings.json
            ClientSecrets = { new Secret("MySecretValue".Sha256()) },
            AllowedScopes = { "WebApplication4.ServerAPI", "openid", "profile" }
        });
    });

以及请求:

POST /connect/token HTTP/1.1
Host: localhost:44388
Content-Type: application/x-www-form-urlencoded
Content-Length: 168

grant_type=password&username=example%40example.com&password=Password1!&client_id=WebApplication4.Integration&scope=WebApplication4.ServerAPI&client_secret=MySecretValue

终于成功了,正常的登录流程也成功了!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有个人帐户和 ASP.NET Core 托管的 Blazor WebAssembly 应用程序 - 令牌请求 - “错误”:“unauthorized_client” 的相关文章

随机推荐