如何解决GetDiscoveryDocumentAsync失败,IdentityServer4客户端
我有一个帮助器类,用于从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,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,这是问题所在
alerts.json
HttpClient不应该被重用/缓存,而是应该在每次使用后进行处理,因为否则可能会发出各种不同的信息,例如DNS或TCP / IP端口用完。
但是更好的是,为什么不将发现文档缓存X分钟呢?该文档不会经常更改。
请参阅以下文章:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。