简体   繁体   English

Blazor WebAssembly 应用程序与个人帐户和 ASP.NET 核心托管 - 令牌请求 - “错误”:“unauthorized_client”

[英]Blazor WebAssembly App with Individual Accounts and ASP.NET Core Hosted - Token request - "error": "unauthorized_client"

Creating a new Blazor WebAssembly App with Microsoft Visual Studio 2019 Version 16.9.4 with these specifications: Target Framework .NET 5.0 , Authentication Type Individual Accounts and ASP.NET Core Hosted :使用具有以下规范的Microsoft Visual Studio 2019 Version 16.9.4创建新的Blazor WebAssembly AppTarget Framework .NET 5.0Authentication Type Individual AccountsASP.NET Core Hosted

在此处输入图像描述

Gives a Server project with these NuGet s at version 5.0.5 :在版本5.0.5中提供具有这些NuGet的服务器项目:

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

Startup.cs contains this code: Startup.cs 包含以下代码:

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

services.AddAuthentication()
    .AddIdentityServerJwt();

Reading the blog post ASP.NET Core Authentication with IdentityServer4 from Microsoft I should be able to retrieve a token with a sample request that looks like this:阅读博客文章ASP.NET Core Authentication with IdentityServer4 from 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/

Creating a request that looks like that but for the solution created:创建一个看起来像这样的请求,但针对创建的解决方案:

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

This request returns HTTP Status 400 Bad Request with body:此请求返回 HTTP 状态 400 错误请求,正文:

{
    "error": "unauthorized_client"
}

在此处输入图像描述

I'm pretty sure the values are correct since I got client_id and scope from the request used to sign in to the web application.我很确定这些值是正确的,因为我从用于登录 web 应用程序的请求中获得了client_idscope That flow does not use grant_type=password though.不过,该流程不使用grant_type=password Example request from login:来自登录的示例请求:

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

Confirmation that the user exists and works:确认用户存在并工作:

在此处输入图像描述

What am I missing?我错过了什么?

TLDR: TLDR:

Remove this from appsettings.json :appsettings.json删除它:

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

Edit Startup.cs :编辑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" }
        });
    });

This request will work:此请求将起作用:

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

Long answer:长答案:

I started out with trying to get a better error messages with Logging.我开始尝试使用 Logging 获得更好的错误消息。

I added the code below to public static IHostBuilder CreateHostBuilder(string[] args) in Program.cs :我将以下代码添加到Program.cs中的public static IHostBuilder CreateHostBuilder(string[] args)

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

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

When debugging I could then show output from the Server application when I made the request.在调试时,我可以在发出请求时从服务器应用程序中显示 output。 It looked like this:它看起来像这样:

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": "example@example.com",
          "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"
      }

The error message to look at is Client not authorized for resource owner flow, check the AllowedGrantTypes setting{ client_id = WebApplication4.Client } .要查看的错误消息是Client not authorized for resource owner flow, check the AllowedGrantTypes setting{ client_id = WebApplication4.Client }

在此处输入图像描述

With this error message I found this Question:有了这个错误消息,我发现了这个问题:

Question about ASP.NET Core 3 Identity / Identity Server / SPA support for Resource Owner Password Grant Type 关于 ASP.NET Core 3 Identity / Identity Server / SPA 对资源所有者密码授予类型的支持的问题

There I could read在那里我可以阅读

found that the allowed grant type of password was not being added when the profile is set to IdentityServerSPA.发现当配置文件设置为 IdentityServerSPA 时,未添加允许的密码授予类型。

Looking at appsettings.json the application uses that profile:查看appsettings.json应用程序使用该配置文件:

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

Looking at Microsoft Application profiles what it actually does is this:查看Microsoft Application profiles它的实际作用是:

  • The redirect_uri defaults to /authentication/login-callback. redirect_uri 默认为 /authentication/login-callback。
  • The post_logout_redirect_uri defaults to /authentication/logout-callback. post_logout_redirect_uri 默认为 /authentication/logout-callback。
  • The set of scopes includes the openid, profile, and every scope defined for the APIs in the app.范围集包括为应用程序中的 API 定义的 openid、配置文件和每个 scope。
  • The set of allowed OIDC response types is id_token token or each of them individually (id_token, token).允许的 OIDC 响应类型集是 id_token 令牌或每个单独的(id_token、令牌)。
  • The allowed response mode is fragment.允许的响应模式是片段。

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

Before starting to modify this I visited the URL https://localhost:44388/.well-known/openid-configuration to get the current configuration.在开始修改之前,我访问了 URL https://localhost:44388/.well-known/openid-configuration以获取当前配置。 It looked like this and specifically says grant_types_supported: ...password :它看起来像这样,特别是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
}

For some reason IdentityServer Clients can not be configured in code and in appsettings.json .由于某种原因,无法在代码和appsettings.json中配置IdentityServer Clients I therefore removed Clients from appsettings.json and added this to Startup.cs:因此,我从appsettings.json中删除了Clients并将其添加到 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 it did not work, OidcConfigurationController got an exception for ClientRequestParametersProvider.GetClientParameters(HttpContext, clientId);没有WithRedirectUriWithLogoutRedirectUri它不起作用, OidcConfigurationController得到了ClientRequestParametersProvider.GetClientParameters(HttpContext, clientId); with System.InvalidOperationException: 'Sequence contains no elements' . with System.InvalidOperationException: 'Sequence contains no elements' For some reason this is fixed automatically when using appsettings.json .由于某种原因,使用appsettings.json时会自动修复此问题。

I now got the error message when posting to /connect/token :我现在在发布到/connect/token时收到错误消息:

{
    "error": "invalid_client"
}

But I got a much better error in the log:但是我在日志中得到了一个更好的错误:

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

Added a secret to Startup.cs :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" }
        });
    });

And the request:和请求:

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

It finally worked and the normal login flow worked as well!它终于奏效了,正常的登录流程也奏效了!

在此处输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Blazor WebAssembly 应用程序与个人帐户和 ASP.NET 核心托管 - 禁用用户注册 - Blazor WebAssembly App with Individual Accounts and ASP.NET Core Hosted - Disable user registration Blazor WebAssembly 应用程序与个人帐户和 ASP.NET 核心托管 - IIS - SQLLocalDB 15.0 找不到指定的资源语言 ID - Blazor WebAssembly App with Individual Accounts and ASP.NET Core Hosted - IIS - SQLLocalDB 15.0 The specified resource language ID cannot be found 部署托管到 Azure 的 Blazor WebAssembly 应用 ASP.NET Core - Deploy Blazor WebAssembly App ASP.NET Core hosted to Azure 如何使用 ASP.NET 核心托管发布 Blazor WebAssembly - How to publish Blazor WebAssembly with ASP.NET Core hosted 在 ASP.NET 核心 Web 应用程序中使用存储在应用程序中的单个用户帐户模拟登录时出现 400 错误请求错误 - 400 Bad Request error when simulating login with Postman on ASP.NET Core Web Application with individual user accounts stored in-app Blazor Webassembly (PWA) 是否支持独立的 session 存储(不在 asp.net 内核中托管)? - Is session storage supported in Blazor Webassembly (PWA) standalone (Not hosted in asp.net core)? 托管在 ASP.NET Core 项目上的 Blazor Webassembly 项目中的身份验证问题 - Problem with Authentification in Blazor Webassembly project which hosted on ASP.NET Core project ClaimTypes.NameIdentifier 在 Blazor WebAssembly ASP.NET 核心托管中始终返回 null - ClaimTypes.NameIdentifier returns always null in Blazor WebAssembly ASP.NET Core Hosted 从 Blazor WebAssembly (WASM) 项目调用外国 API(**不是** ASP.Net Core,托管) - Call an foreign API from a Blazor WebAssembly (WASM) Project (**NOT** ASP.Net Core, hosted) 移动呈现不正确 Azure 应用服务 Blazor Webassembly(ASP.NET 托管) - Mobile Renders Incorrectly Azure App Service Blazor Webassembly (ASP.NET Hosted)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM