[英]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 App
: Target Framework .NET 5.0
, Authentication Type Individual Accounts
和ASP.NET Core Hosted
:
Gives a Server project with these NuGet
s at version 5.0.5
:在版本
5.0.5
中提供具有这些NuGet
的服务器项目:
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_id
和scope
。 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
它的实际作用是:
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);
没有
WithRedirectUri
和WithLogoutRedirectUri
它不起作用, 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.