使用 IHttpClientFactory 和 Intercept HttpClient GetAsync 时无法从 Identity Server 4 获取访问令牌

问题描述 投票:0回答:2

我正在尝试从 .Net 6 解决方案中的 Identity Server 4 获取访问令牌。我有 3 个项目正在运行: Identity Server从中获取访问令牌 Movies.API 用于访问受保护的资源 Movies.Client 调用 api 并使用我使用 http 消息处理程序从 Identity Server 获取的访问令牌获取安全资源

这是我的身份服务器配置代码(相关客户端):

public class Config
{
    public static IEnumerable<Client> Clients =>
        new Client[]
        {
            new Client
               {
                    ClientId = "movieClient",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets =
                    {
                        new Secret("secret".Sha256())
                    },
                    AllowedScopes = { "movieAPI" } // as the name in ApiScopes static list 
               },
            new Client
               {
                   ClientId = "movies_mvc_client",
                   ClientName = "Movies MVC Web App",
                   AllowedGrantTypes = GrantTypes.Code,
                   RequirePkce = false,
                   AllowRememberConsent = false,
                   RedirectUris = new List<string>()
                   {
                       "https://localhost:5002/signin-oidc"
                   },
                   PostLogoutRedirectUris = new List<string>()
                   {
                       "https://localhost:5002/signout-callback-oidc"
                   },
                   ClientSecrets = new List<Secret>
                   {
                       new Secret("secret".Sha256())
                   },
                   AllowedScopes = new List<string>
                   {
                       IdentityServerConstants.StandardScopes.OpenId,
                       IdentityServerConstants.StandardScopes.Profile,

                   }
            }
        };



    public static IEnumerable<ApiScope> ApiScopes =>
       new ApiScope[]
       {
           new ApiScope("movieAPI","Movie API")
       };

// rest of the code ...

这是服务 GetMovies() 中注入的 IHttpClientFactory :

public async Task<IEnumerable<Movie>> GetMovies()
    {
        // ** OPTION 1 **
        var httpClient = _httpClientFactory.CreateClient("MovieAPIClient");
    
        var request = new HttpRequestMessage(HttpMethod.Get, "/api/movies/");

        // using the handler
        var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
    
        response.EnsureSuccessStatusCode();
    
        var content = await response.Content.ReadAsStringAsync();
    
        var movieList = JsonConvert.DeserializeObject<List<Movie>>(content);
    
        return movieList;
        ...

以下是请求处理程序的实现: enter image description here

最后是在 Movie.Client Program.cs 中注册 HttpClient :

// 1- create an httpclient used for accessing in Movies.API
builder.Services.AddTransient<AuthenticationDelegatingHandler>();

builder.Services.AddHttpClient("MovieAPIClient", client =>
{
    client.BaseAddress = new Uri("https://localhost:5001/");
    client.DefaultRequestHeaders.Clear();
    client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
}).AddHttpMessageHandler<AuthenticationDelegatingHandler>();


// 2- create an httpclient used for accessing in the IDP
builder.Services.AddHttpClient("IDPClient", client =>
{
    client.BaseAddress = new Uri("https://localhost:5005/");
    client.DefaultRequestHeaders.Clear();
    client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
}).AddHttpMessageHandler<AuthenticationDelegatingHandler>();


builder.Services.AddSingleton(new ClientCredentialsTokenRequest
{
    Address = "https://localhost:5005/connect/token",
    ClientId = "movieClient",
    ClientSecret = "secret",
    Scope = "movieAPI"
});

现在正在调试中:每次点击继续按钮时,我都会再次返回到处理程序中的 SendAsync() 。

有人可以帮我解决这个问题吗? 谢谢你。

c# .net-6.0 identityserver4 httpclientfactory httpinterceptor
2个回答
0
投票

您面临的问题是无限循环,因为您对获取电影的请求和获取 accessToken 的请求使用相同的

httpClient

使用 httpClient 的每个请求都会经过

AuthenticationDelegatingHandler

为了解决您的问题,这就是我的解决方案。

  1. 更新请求处理程序
public class AuthenticationDelegatingHandler : DelegatingHandler{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly ClientCredentialsTokenRequest _tokenRequest;

    public AuthenticationDelegatingHandler(IHttpClientFactory httpClientFactory, ClientCredentialsTokenRequest tokenRequest){
        _httpClientFactory = httpClientFactory;
        _tokenRequest = tokenRequest;
    }

    protected override async Task<IHttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken){
        // HttpClientFactory will create a new httpClient different from the one registered in Program.cs
        var httpClient =  _httpClientFactory.CreateClient();

        var tokenResponse = await httpClient.RequestClientCredentialsTokenAsync(_tokenRequest);
        if(tokenResponse.IsError){
            throw new HttpRequestException("Something went wrong while requesting the access token");
        }

        request.SetBearerToken(tokenResponse.AccessToken);

        return await base.SendAsync(request, cancellationToken);
    }
}

0
投票

我发现问题了!,这是因为我在“IDPClient”上使用处理程序,它应该由 Identity Server 4 端处理。

之前

// 2- create an httpclient used for accessing in the IDP
    builder.Services.AddHttpClient("IDPClient", client =>
    {
        client.BaseAddress = new Uri("https://localhost:5005/");
        client.DefaultRequestHeaders.Clear();
        client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
    }).AddHttpMessageHandler<AuthenticationDelegatingHandler>(); // remove the handler

之后

// 2- create an httpclient used for accessing in the IDP
builder.Services.AddHttpClient("IDPClient", client =>
{
    client.BaseAddress = new Uri("https://localhost:5005/");
    client.DefaultRequestHeaders.Clear();
    client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
});

它会起作用的!

© www.soinside.com 2019 - 2024. All rights reserved.