简体   繁体   English

GetDiscoveryDocumentAsync 失败,IdentityServer4 客户端

[英]GetDiscoveryDocumentAsync failed, IdentityServer4 client

I have a helper class to get access token from IdentityServer4.我有一个帮助类从 IdentityServer4 获取访问令牌。 Here is the code:这是代码:

public class ServerTokenHelper
{
    static TokenResponse Token { get; set; }
    static DateTime ExpiryTime { get; set; }

    string  _host;
    string _clientId;
    string _clientSecret;
    string _clientScopes;

    static object ThreadLock = new object();


    static ConcurrentDictionary<string, Tuple<string, string, TokenResponse, DateTime>> userNameCache =
        new ConcurrentDictionary<string, Tuple<string, string, TokenResponse, DateTime>>();
    private static HttpClient _tokenClient = new HttpClient();

    public ServerTokenHelper(string commAddress, string host, string clientId, string clientSecret, string clientScopes)
    {
        _host = host;
        _clientId = clientId;
        _clientSecret = clientSecret;
        _clientScopes = clientScopes;
    }
        public async Task<TokenResponse> GetUserTokenResponseAsync(string userName, string password)
    {
        if (userName != null && userName.Length > 0)
        {
            lock (ThreadLock)
            {
                if (userNameCache.TryGetValue(userName, out var cacheItem))
                {
                    // Since we always cache the result below, we should verify before reusing an entry that the IdentityToken
                    // isn't null because of an error getting it last time!
                    if (cacheItem.Item2 == password && cacheItem.Item3 != null && cacheItem.Item3.IdentityToken != null
                        && cacheItem.Item4 > DateTime.UtcNow)
                    {
                        // System.Diagnostics.Debug.WriteLine($"GetUserTokenResponseAsync({userName}): returning cached value");
                        return cacheItem.Item3;
                    }
                }
            }
        }

        Trace.WriteLine($"GetUserTokenResponseAsync({userName}): new token being retrieved...");

        bool blHttps = false;
        if (_host.ToLower().Contains("https")) blHttps = true;
        var disco = await _tokenClient.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest
        {
            Address = _host,
            Policy = { RequireHttps = blHttps }
        });
        if (disco.IsError)
        {
            Trace.WriteLine($"GetUserTokenResponseAsync({userName}): GetDiscoveryDocumentAsync failed: {disco.Error}");
            return null;
        }
        // request token
        var tokenResponse = await _tokenClient.RequestPasswordTokenAsync(new PasswordTokenRequest
        {
            Address = disco.TokenEndpoint,
            ClientId = _clientId,
            ClientSecret = _clientSecret,
            Scope = _clientScopes,
            UserName = userName,
            Password = password
        });
        if (tokenResponse.IsError)
        {
            Trace.WriteLine($"GetUserTokenResponseAsync({userName}): Could not retrieve token. {tokenResponse.Error} - {tokenResponse.ErrorDescription}");
        }

        lock (ThreadLock)
        {
            userNameCache[userName] = Tuple.Create(userName, password, tokenResponse,
                DateTime.UtcNow.AddSeconds((tokenResponse != null) ? tokenResponse.ExpiresIn - 120 : 0));
        }

        return tokenResponse;
    }

} The intent of above codes is to get access token for User Resources Password flow.以上代码的目的是获取用户资源密码流的访问令牌。 Recently, someone changed from最近,有人变了

private HttpClient _tokenClient = new HttpClient();

to

private static HttpClient _tokenClient = new HttpClient();

With this change, we got some errors occasionally.通过这种更改,我们偶尔会遇到一些错误。 The code function is in production server.代码功能在生产服务器中。 There may be several thousands of api calls each hour.每小时可能有数千个 api 调用。 Here is the error message:这是错误消息:

GetUserTokenResponseAsync: GetDiscoveryDocumentAsync failed

Can someone explain what is the issue caused by this simple change?有人能解释一下这个简单的变化引起的问题是什么吗?

With HttpClient this line is the problem使用 HttpClient 这一行就是问题所在

private static HttpClient _tokenClient = new HttpClient();

HttpClient is not supposed to be reused/cached, instead you are supposed to dispose it after each use, because you might otherwise get various issued, like DNS or that you run out of TCP/IP ports. HttpClient 不应该被重用/缓存,而是应该在每次使用后处理它,因为否则您可能会收到各种问题,例如 DNS 或 TCP/IP 端口用完。

But even better, why not cache the discovery document for X minutes?但更好的是,为什么不将发现文档缓存 X 分钟? That document does not change that often.该文件不会经常更改。

See these articles:请参阅这些文章:

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM