我想要实现的是HttpClient,只要服务器抛出401,就可以获得新的承载令牌。令牌每30分钟到期一次我想更新它,但修改标题并不是线程安全的(据我所知)并且如果一个线程尝试更新授权而另一个线程将导致问题正试图提出请求。
public class MyCustomClient : HttpClient
{
public MyCustomClient(Configuration config)
:base()
{
this.BaseAddress = new Uri(config.ServiceUrl);
this.Timeout = new TimeSpan(0, 2, 0);
this.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task UpdateBearerTokenAsync()
{
var token = "123" // assume this was retrieved from server successfully
this.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
}
我理想情况下只需要一次重新授权,以及所有其他调用等待客户端当前正在尝试重新进行身份验证。
第一部分我认为我可以使用SemaphoreSlim
private readonly SemaphoreSlim _bearerTokenSemaphore;
public MyCustomClient(Configuration config)
:base()
{
_bearerTokenSemaphore = new SemaphoreSlim(0, 1);
_bearerTokenSemaphore.Release();
this.BaseAddress = new Uri(config.ServiceUrl);
this.Timeout = new TimeSpan(0, 2, 0);
this.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<bool> UpdateBearerTokenAsync()
{
if (!_bearerTokenSemaphore.Wait(0))
{
return false;
}
try
{
var token = "123" // assume this was retrieved from server successfully using an asynchronous method
this.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
return true;
}
finally { _bearerTokenSemaphore.Release(); }
}
但是,如果目前正在进行授权,我还不确定如何让所有其他呼叫等待。我试过像
这样的东西public new async Task<HttpResponseMessage> GetAsync(string uri)
{
await _bearerTokenSemaphore.WaitAsync();
_bearerTokenSemaphore.Release();
return await base.GetAsync(uri);
}
但这似乎陷入僵局
编辑:
以上没有用,因为我在实例化之后从未发布过sempahore(woops)。所以这似乎现在有效,但我仍然愿意接受更好的建议,因为我对此实现并不满意