|
httpClient = new HttpClient(new RetryOnUnauthorizedMessageHandler(new HttpClientHandler())); |
|
|
|
/// <summary> |
|
/// See https://stackoverflow.com/a/49304655 |
|
/// </summary> |
|
public class RetryOnUnauthorizedMessageHandler : DelegatingHandler |
|
{ |
|
public RetryOnUnauthorizedMessageHandler(HttpMessageHandler innerHandler) : base(innerHandler) |
|
{ |
|
} |
|
|
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, |
|
CancellationToken cancellationToken) |
|
{ |
|
var response = await base.SendAsync(request, cancellationToken); |
|
//test for 401 and actual bearer token in initial request |
|
var wasAuthorized = !string.IsNullOrWhiteSpace(request.Headers.Authorization?.Parameter); |
|
|
|
|
|
if (response.StatusCode != HttpStatusCode.Unauthorized || !wasAuthorized) return response; // authorized or no token is needed |
|
|
|
//if 401 |
|
|
|
try |
|
{ |
|
var log = Mvx.Resolve<IMvxLog>(); |
|
log.Info("Got Unauthorized, trying to refresh token"); |
|
var uow = Mvx.Resolve<IUnitOfWork>(); |
|
var model = uow.Token.Get(); |
|
var data = new Dictionary<string, string> |
|
{ |
|
{"grant_type", "refresh_token"}, |
|
{"refresh_token", model.RefreshToken} |
|
}; |
|
var requestUri = new Uri($"{Constants.UriAuthApi}api/token"); |
|
var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri) |
|
{ |
|
Content = new FormUrlEncodedContent(data) |
|
}; |
|
using (var refreshResponse = await base.SendAsync(requestMessage, cancellationToken).ConfigureAwait(false)) |
|
{ |
|
if (refreshResponse.StatusCode == HttpStatusCode.Unauthorized) |
|
{ |
|
log.Error("Refresh token is not valid. Signing out"); |
|
await Mvx.Resolve<IMvxNavigationService>() |
|
.CustomNavigate<LoginContainerViewModel>(NavigationType.ClearBackstack); |
|
} |
|
else if(refreshResponse.IsSuccessStatusCode) |
|
{ |
|
var rawResponse = await refreshResponse.Content.ReadAsStringAsync(); |
|
var authModel = JsonConvert.DeserializeObject<AuthModel>(rawResponse); |
|
log.Info($"Successfully refreshed token: {authModel.AccessToken.Substring(0, 7)}..."); |
|
request.Headers.Remove("Authorization"); |
|
request.Headers.Add("Authorization", "bearer " + authModel.AccessToken); |
|
if (uow.Token.Update(authModel)) |
|
{ |
|
log.Info("Token saved, retying initial request..."); |
|
response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false); |
|
} |
|
} |
|
else |
|
{ |
|
//TODO |
|
} |
|
|
|
} |
|
return response; |
|
} |
|
catch (Exception e) |
|
{ |
|
Analytics.TrackEvent("Token refresh failed"); |
|
throw e; |
|
} |
|
} |
|
} |
|
|
|
//when creating httpClient like this - requests are very slow |
|
httpClient = new HttpClient(new RetryOnUnauthorizedMessageHandler(new HttpClientHandler())); |
|
//but when doing like this - everything works fast (but no desired behaviour) |
|
httpClient = new HttpClient(new HttpClientHandler()); |