c# - c# HttpRequestMessage Authorization 使用 IdentityServer 返回 401
问题描述
我有一个用于演示目的的 IdentityServer4 服务器(我已按照 IdentityServer4 文档中的入门指南进行操作)。我能够从中获取令牌,并且在使用 Postman 时,我能够使用此令牌从受保护的资源中获取信息。
但是当我尝试从我的 c# 代码中使用这个令牌时,我得到一个 401 响应(Postman 中的相同令牌工作正常)。我在代码中设置请求的方式如下:
httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "{token string}");
我知道服务器接受令牌。我添加了一个控制台来将令牌写入到服务器的不同请求中,并将其与我使用 Postman 得到的进行比较。这是我的输出:
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 POST http://localhost:5000/connect/token application/x-www-form-urlencoded 87
>>>>>>>>>>>>> PATH: /connect/token
>>>>>>>>>>>>> AUTH:
dbug: IdentityServer4.Hosting.EndpointRouter[0]
Request path /connect/token matched to endpoint type Token
dbug: IdentityServer4.Hosting.EndpointRouter[0]
Endpoint enabled: Token, successfully created handler: IdentityServer4.Endpoints.TokenEndpoint
info: IdentityServer4.Hosting.IdentityServerMiddleware[0]
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.TokenEndpoint for /connect/token
dbug: IdentityServer4.Endpoints.TokenEndpoint[0]
Start token request.
dbug: IdentityServer4.Validation.ClientSecretValidator[0]
Start client validation
dbug: IdentityServer4.Validation.BasicAuthenticationSecretParser[0]
Start parsing Basic Authentication secret
dbug: IdentityServer4.Validation.PostBodySecretParser[0]
Start parsing for secret in post body
dbug: IdentityServer4.Validation.SecretParser[0]
Parser found secret: PostBodySecretParser
dbug: IdentityServer4.Validation.SecretParser[0]
Secret id found: client
dbug: IdentityServer4.Stores.ValidatingClientStore[0]
client configuration validation for client client succeeded.
dbug: IdentityServer4.Validation.SecretValidator[0]
Secret validator success: HashedSharedSecretValidator
dbug: IdentityServer4.Validation.ClientSecretValidator[0]
Client validation success
dbug: IdentityServer4.Validation.TokenRequestValidator[0]
Start token request validation
dbug: IdentityServer4.Validation.TokenRequestValidator[0]
Start client credentials token request validation
dbug: IdentityServer4.Validation.TokenRequestValidator[0]
client credentials token request validation success
info: IdentityServer4.Validation.TokenRequestValidator[0]
Token request validation success, {
"ClientId": "client",
"GrantType": "client_credentials",
"Scopes": "api1",
"Raw": {
"grant_type": "client_credentials",
"client_id": "client",
"client_secret": "***REDACTED***",
"username": "",
"password": "***REDACTED***"
}
}
dbug: IdentityServer4.Services.DefaultClaimsService[0]
Getting claims for access token for client: client
dbug: IdentityServer4.Endpoints.TokenEndpoint[0]
Token request success.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 343.2786ms 200 application/json; charset=UTF-8
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/api/values/ application/json; charset=utf-8 4
>>>>>>>>>>>>> PATH: /api/values/
>>>>>>>>>>>>> AUTH: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjYyNGM5MmFkZGZmNGMzN2I1ZDFmMTdmZjI2ZGQ4MmQ0IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1Njc5MzMwMTcsImV4cCI6MTU2NzkzNjYxNywiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjpbImh0dHA6Ly9sb2NhbGhvc3Q6NTAwMC9yZXNvdXJjZXMiLCJhcGkxIl0sImNsaWVudF9pZCI6ImNsaWVudCIsInNjb3BlIjpbImFwaTEiXX0.wILiCZ_H8-8ZyIYjxwt_Z7Mixr6wk1bwF0n2MTLrSkT7lZUShM1LFrmRaMAj37vJMN86a4q-WmBfqWhsxmfn8IqYn7GwlWOFIzbeHgaiqL0I4FsBPNzXNmBt_jkmMVwfLrxFWQ7b-6rucXvcNJjr9hUKQ-3jhF3nw7Za9D-YclnBH8NOOg5V1z7lTQOAU-5B7YbZut9uh1RYnOO2Spqg-EQ8Qd00Yy4sdNLidH1yZi6MoTgNhqmx4mV64oQERrdAzMPdw2-DlWYk8Ujd-qixNwCHHAlA35XlQZFHnZSrOrJwTNJBF-xGypbBQvLtqbWxD3ZnvuZcQ-ItGiIF9CFX-g
info>>>>>>>>>>>>> PATH: /.well-known/openid-configuration
>>>>>>>>>>>>> AUTH:
: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/.well-known/openid-configuration
dbug: IdentityServer4.Hosting.EndpointRouter[0]
Request path /.well-known/openid-configuration matched to endpoint type Discovery
dbug: IdentityServer4.Hosting.EndpointRouter[0]
Endpoint enabled: Discovery, successfully created handler: IdentityServer4.Endpoints.DiscoveryEndpoint
info: IdentityServer4.Hosting.IdentityServerMiddleware[0]
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.DiscoveryEndpoint for /.well-known/openid-configuration
dbug: IdentityServer4.Endpoints.DiscoveryEndpoint[0]
Start discovery request
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 44.5515ms 200 application/json; charset=UTF-8
>>>>>>>>>>>>> PATH: /.well-known/openid-configuration/jwks
>>>>>>>>>>>>> AUTH:
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/.well-known/openid-configuration/jwks
dbug: IdentityServer4.Hosting.EndpointRouter[0]
Request path /.well-known/openid-configuration/jwks matched to endpoint type Discovery
dbug: IdentityServer4.Hosting.EndpointRouter[0]
Endpoint enabled: Discovery, successfully created handler: IdentityServer4.Endpoints.DiscoveryKeyEndpoint
info: IdentityServer4.Hosting.IdentityServerMiddleware[0]
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.DiscoveryKeyEndpoint for /.well-known/openid-configuration/jwks
dbug: IdentityServer4.Endpoints.DiscoveryKeyEndpoint[0]
Start key discovery request
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 26.8755ms 200 application/jwk-set+json; charset=UTF-8
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[2]
Successfully validated the token.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 242.3834ms 307
info: Microsoft.AspNetCore.Server.Kestrel[32]
Connection id "0HLPK7A0C1DTP", Request id "0HLPK7A0C1DTP:00000001": the application completed without reading the entire request body.
info>>>>>>>>>>>>> PATH: /api/values/
>>>>>>>>>>>>> AUTH:
: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET https://localhost:5001/api/values/ application/json; charset=utf-8 4
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint 'AuthServerDemo.Controllers.ValuesController.Get (AuthServerDemo)'
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
Route matched with {action = "Get", controller = "Values"}. Executing controller action with signature Microsoft.AspNetCore.Mvc.ActionResult`1[System.Collections.Generic.IEnumerable`1[System.String]] Get() on controller AuthServerDemo.Controllers.ValuesController (AuthServerDemo).
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
Executing ChallengeResult with authentication schemes ().
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12]
AuthenticationScheme: Bearer was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action AuthServerDemo.Controllers.ValuesController.Get (AuthServerDemo) in 27.7154ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'AuthServerDemo.Controllers.ValuesController.Get (AuthServerDemo)'
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 88.7948ms 401
info: Microsoft.AspNetCore.Server.Kestrel[32]
Connection id "0HLPK7A0C1DTR", Request id "0HLPK7A0C1DTR:00000001": the application completed without reading the entire request body.
调用api/values
端点时,我看到请求被令牌接受。然后它调用.well-known/openid-configuration
,然后调用.well-known/openid-configuration/jwks
,然后再调用 ,api/values
但这次使用的是空的授权令牌。
如果我将此与 Postman 调用进行比较,那么在对api/values
端点的第二次调用中,它确实具有授权令牌。
我的请求设置中缺少什么?有人可以解释在服务器端进行的额外调用以及为什么调用api/values
两次?
解决方案
您需要在 API 项目中配置 IdentityServer EndPoint,如下所示
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore()
.AddAuthorization()
.AddJsonFormatters();
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:5000";//IdentityServer4 Endpoint
options.RequireHttpsMetadata = false;
options.ApiName = "api1";//Name of resource
});
}
推荐阅读
- php - 单元测试 DB:: 在 Laravel 中使用 PhpUnit 调用
- azure - 在 Azcopy 上更改层级
- nestjs - 如何在 TypeORM 中创建用户表和个人资料之间的一对一关系,可以是学生或教师?
- arrays - 查找数组中的最大值
- python - 如何通过使用python添加来获取目标
- spring - 无法将“java.lang.String”转换为“java.time.LocalDateTime”(Spring)
- docker - Gulp Webpack 没有在 docker 中观看文件
- azure - 从 Token Provider 获取的 Token 在 azure 中是错误的 issue
- javascript - 在反应中将 Material UI 组件作为道具传递
- python - 如何使用 python ssl 为 tls 连接设置证书