[英]GetDiscoveryDocumentAsync failed, IdentityServer4 client
我有一個幫助類從 IdentityServer4 獲取訪問令牌。 這是代碼:
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;
}
以上代碼的目的是獲取用戶資源密碼流的訪問令牌。 最近,有人變了
private HttpClient _tokenClient = new HttpClient();
到
private static HttpClient _tokenClient = new HttpClient();
通過這種更改,我們偶爾會遇到一些錯誤。 代碼功能在生產服務器中。 每小時可能有數千個 api 調用。 這是錯誤消息:
GetUserTokenResponseAsync: GetDiscoveryDocumentAsync failed
有人能解釋一下這個簡單的變化引起的問題是什么嗎?
使用 HttpClient 這一行就是問題所在
private static HttpClient _tokenClient = new HttpClient();
HttpClient 不應該被重用/緩存,而是應該在每次使用后處理它,因為否則您可能會收到各種問題,例如 DNS 或 TCP/IP 端口用完。
但更好的是,為什么不將發現文檔緩存 X 分鍾? 該文件不會經常更改。
請參閱這些文章:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.