Hej, robię WebApplication. Mam WebApi, z którym się łączę po HTTPS.
I teraz tak. Na początku idzie logowanie - WebAPI loguje użytkownika po przekazaniu danych i odsyła Bearer Token i Refresh Token.
Następnie WebApplication trzyma sobie oba te tokeny. Bearer token jest oczywiście dodawany do headera każdego requestu, który idzie do WebApi. I po 15 minutach Bearer token traci swoją ważność. W tym momencie aplikacja powinna zdobyć nowy BearerToken za pomocą RefreshTokena.
Zrobiłem to w bardzo prosty sposób. Wszystkie żądania idą mi przez tą metodę:
public async Task<HttpResponseMessage> SendAsyncRequest(string uri, string content, HttpMethod method, bool tryReauthorizeOn401 = true)
{
try
{
HttpRequestMessage rm = new HttpRequestMessage(method, uri);
if (!string.IsNullOrWhiteSpace(content))
rm.Content = new StringContent(content, Encoding.UTF8, ContentType);
HttpResponseMessage response = await httpClient.SendAsync(rm);
if (response.StatusCode == HttpStatusCode.Unauthorized && tryReauthorizeOn401)
{
httpClient.CancelPendingRequests();
bool res = await OnReauthorizeUser();
if (!res)
return response;
return await SendAsyncRequest(uri, content, method, false);
}
return response;
}catch(Exception ex)
{
Debug.Assert(false, ex.Message);
throw;
}
}
Jak to powinno zadziałać? Tak:
- wykonuję żądanie
- jeśli dostanę 401 i mam spróbować się reautoryzować (tryReauthorizeOn401), wtedy wywołuję zdarzenie:
OnReauthorizeUser
- w obsłudze tego zdarzenia (czego tu nie widać) w końcu wywołuję znowu
SendAsyncRequest
z danymi, które mają mi zwrócić nowe tokeny.
Spodziewałem się, że to zadziała, jednak nie działa. Okazuje się, że przy wywołaniu SendAsynRequest z danymi reautoryzacyjnymi, otrzymuję wyjątek TaskCancelletionException. Od razu tutaj httpClient.SendAsync(rm);
. Bez żadnego timeout'a, bez niczego. Momentalnie. Zatem kod wraca do miejsca po OnReauthorizeUser z res = false.
I teraz wymyśliłem sobie, że być może "zaburzam" cykl życia requestu w WebApplication. Bo wydaje mi się, że podczas jednego requestu (np. kliknięcie użytkownika na link z chronionym zasobem) próbuję wykonać dwa żądania:
- Pobranie chronionego zasobu
- Reautoryzację, zamiast główny request się skończy.
Czy dobrze rozumuję? Jak uniknąć takich problemów? Co powinienem zrobić, żeby:
- W momencie otrzymania błędu 401, system automatycznie spróbował odświeżyć sobie tokeny i wywołał żądanie jeszcze raz?
Innymi słowy:
- user klika w "Pokaż moje dokumenty"
- idzie żądanie do WebAPI: "/documents/user/user-id"
- żądanie wraca z odpowiedzią: 401
- reautoryzuję użytkownika: "/tokens/refresh/"
- żądanie wraca z nowymi tokenami (zakładamy dla prostoty, że tak będzie)
- idzie powtórne żądanie do WebApi z kroku 2 "/documents/user/user-id"
Czyli chcę osiągnąć to, że użytkownik klika w link RAZ i normalnie widzi listę swoich dokumentów bez konieczności ponownego logowania (zakładamy oczywiście, że jest zalogowany, bearer token wygasł mu w naturalny sposób i posiada poprawny refresh token)