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:

  1. Pobranie chronionego zasobu
  2. 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)