首页 > 解决方案 > 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两次?

标签: c#asp.net-coreidentityserver4

解决方案


您需要在 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
    });

}

推荐阅读