Chciałbym zaimplementować uwierzytelnianie oparte na JWT w naszym nowym interfejsie API REST. Ale skoro wygaśnięcie jest ustawione w tokenie, czy można go automatycznie przedłużyć? Nie chcę, aby użytkownicy musieli logować się co X minut, jeśli w tym okresie aktywnie korzystali z aplikacji. To byłaby ogromna awaria UX.
Ale przedłużenie ważności powoduje utworzenie nowego tokena (i stary jest nadal ważny, aż do wygaśnięcia). A generowanie nowego tokena po każdym żądaniu wydaje mi się głupie. Brzmi jak problem z bezpieczeństwem, gdy więcej niż jeden token jest ważny jednocześnie. Oczywiście mógłbym unieważnić stary używany przy użyciu czarnej listy, ale musiałbym przechowywać tokeny. Jedną z zalet JWT jest brak pamięci.
Odkryłem, jak Auth0 to rozwiązało. Używają nie tylko tokenu JWT, ale także tokenu odświeżania: https://docs.auth0.com/refresh-token
Ale ponownie, aby to zaimplementować (bez Auth0) musiałbym przechowywać tokeny odświeżania i zachować ich wygaśnięcie. Jaka jest zatem prawdziwa korzyść? Dlaczego nie mieć tylko jednego tokena (nie JWT) i zachować datę ważności na serwerze?
Czy są inne opcje? Czy użycie JWT nie jest odpowiednie dla tego scenariusza?
Odpowiedzi:
Pracuję w Auth0 i byłem zaangażowany w projektowanie funkcji tokena odświeżania.
Wszystko zależy od rodzaju aplikacji i oto nasze zalecane podejście.
Aplikacje internetowe
Dobrym przykładem jest odświeżenie tokena przed jego wygaśnięciem.
Ustaw datę ważności tokena na jeden tydzień i odświeżaj token za każdym razem, gdy użytkownik otwiera aplikację internetową i co godzinę. Jeśli użytkownik nie otworzy aplikacji przez ponad tydzień, będzie musiał się ponownie zalogować, a to jest akceptowalna aplikacja internetowa UX.
Aby odświeżyć token, interfejs API potrzebuje nowego punktu końcowego, który odbiera prawidłowy, nie wygasły JWT i zwraca ten sam podpisany JWT z nowym polem wygaśnięcia. Następnie aplikacja internetowa gdzieś zapisze token.
Aplikacje mobilne / natywne
Większość aplikacji natywnych loguje się raz i tylko raz.
Chodzi o to, że token odświeżania nigdy nie wygasa i zawsze można go wymienić na prawidłowy JWT.
Problem z tokenem, który nigdy nie wygasa, polega na tym, że nigdy nie oznacza nigdy. Co robisz, jeśli zgubisz telefon? Dlatego musi być w jakiś sposób identyfikowalny przez użytkownika, a aplikacja musi zapewniać sposób cofnięcia dostępu. Zdecydowaliśmy się użyć nazwy urządzenia, np. „IPad Maryo”. Następnie użytkownik może przejść do aplikacji i cofnąć dostęp do „iPada Maryo”.
Innym podejściem jest odwołanie tokena odświeżania dla określonych zdarzeń. Ciekawym wydarzeniem jest zmiana hasła.
Uważamy, że JWT nie jest przydatny w tych przypadkach użycia, dlatego używamy losowo generowanego ciągu i przechowujemy go po naszej stronie.
źródło
W przypadku samodzielnej obsługi autoryzacji (tzn. Nie korzystania z dostawcy takiego jak Auth0) mogą działać następujące czynności:
Flaga „reauth” w zapleczu bazy danych zostanie ustawiona, gdy na przykład użytkownik zresetuje hasło. Flaga zostanie usunięta, gdy użytkownik zaloguje się następnym razem.
Ponadto załóżmy, że masz politykę, zgodnie z którą użytkownik musi logować się co najmniej raz na 72 godziny. W takim przypadku logika odświeżania tokena API sprawdzi również datę ostatniego logowania użytkownika z bazy danych użytkownika i odmówi / zezwoli na odświeżenie tokena na tej podstawie.
źródło
Majstrowałem przy przenoszeniu naszych aplikacji do HTML5 z RESTful apis w backend. Rozwiązaniem, które wymyśliłem, było:
Jak widać, zmniejsza to częste żądania tokenów odświeżania. Jeśli użytkownik zamknie przeglądarkę / aplikację przed wyzwoleniem wywołania odnowienia tokena, poprzedni token wygaśnie z czasem i użytkownik będzie musiał się ponownie zalogować.
Bardziej skomplikowaną strategię można wdrożyć, aby zaspokoić brak aktywności użytkowników (np. Zaniedbano otwartą kartę przeglądarki). W takim przypadku odnowienie wywołania tokena powinno obejmować przewidywany czas wygaśnięcia, który nie powinien przekraczać zdefiniowanego czasu sesji. Aplikacja będzie musiała odpowiednio śledzić ostatnią interakcję użytkownika.
Nie podoba mi się pomysł ustawiania długiego okresu ważności, dlatego takie podejście może nie działać dobrze w przypadku aplikacji natywnych wymagających rzadszego uwierzytelniania.
źródło
Alternatywnym rozwiązaniem dla unieważniania JWT, bez dodatkowego bezpiecznego przechowywania w backendie, jest zaimplementowanie nowej
jwt_version
kolumny liczb całkowitych w tabeli użytkowników. Jeśli użytkownik chce się wylogować lub wygasnąć istniejące tokeny, po prostu zwiększajwt_version
pole.Podczas generowania nowego JWT zakoduj go
jwt_version
do ładunku JWT, opcjonalnie zwiększając wcześniej wartość, jeśli nowy JWT powinien zastąpić wszystkie inne.Podczas sprawdzania poprawności JWT
jwt_version
pole jest porównywane obok,user_id
a autoryzacja jest udzielana tylko wtedy, gdy jest zgodna.źródło
Dobre pytanie - w samym pytaniu jest mnóstwo informacji.
Artykuł Odśwież tokeny: kiedy ich używać i jak wchodzą w interakcje z JWT daje dobry pomysł na ten scenariusz. Niektóre punkty to: -
Zobacz także auth0 / angular-jwt angularjs
W przypadku interfejsu API sieci Web. czytaj Włącz tokeny odświeżania OAuth w aplikacji AngularJS przy użyciu ASP .NET Web API 2 i Owin
źródło
Zaimplementowałem to w PHP za pomocą klienta Guzzle do stworzenia biblioteki klienta dla interfejsu API, ale koncepcja powinna działać na innych platformach.
Zasadniczo emituję dwa tokeny, krótki (5 minut) i długi, który wygasa po tygodniu. Biblioteka klienta używa oprogramowania pośredniego do próby odświeżenia krótkiego tokena, jeśli otrzyma odpowiedź 401 na niektóre żądanie. Następnie spróbuje ponownie wykonać oryginalne żądanie i jeśli będzie w stanie odświeżyć, otrzyma prawidłową odpowiedź, w sposób przezroczysty dla użytkownika. Jeśli się nie powiedzie, po prostu wyśle 401 do użytkownika.
Jeśli wygasł krótki token, ale nadal jest autentyczny, a długi token jest ważny i autentyczny, odświeży krótki token za pomocą specjalnego punktu końcowego w usłudze, który uwierzytelnia długi token (jest to jedyna rzecz, do której można go użyć). Następnie użyje krótkiego tokena, aby uzyskać nowy długi token, przedłużając go o kolejny tydzień za każdym razem, gdy odświeża krótki token.
Takie podejście pozwala nam również cofnąć dostęp w ciągu maksymalnie 5 minut, co jest dopuszczalne do naszego użytku bez konieczności przechowywania czarnej listy tokenów.
Późna edycja: Ponownie przeczytam te miesiące po tym, jak było świeżo w mojej głowie, powinienem zauważyć, że możesz odwołać dostęp podczas odświeżania krótkiego tokena, ponieważ daje to możliwość droższych połączeń (np. Połączenia z bazą danych, aby sprawdzić, czy użytkownik został zbanowany) bez płacenia za to przy każdym pojedynczym połączeniu z Twoją usługą.
źródło
Poniżej znajdują się kroki, aby cofnąć swój token dostępu JWT:
1) Po zalogowaniu wyślij 2 tokeny (token dostępu, token odświeżenia) w odpowiedzi na klienta.
2) Token dostępu będzie miał krótszy czas wygaśnięcia, a Odśwież będzie miał długi czas wygaśnięcia.
3) Klient (interfejs użytkownika) będzie przechowywać token odświeżania w swoim lokalnym magazynie i token dostępu w plikach cookie.
4) Klient użyje tokena dostępu do wywoływania api. Ale kiedy wygaśnie, wybierz token odświeżania z pamięci lokalnej i wywołaj interfejs serwera autoryzacji, aby pobrać nowy token.
5) Na Twoim serwerze autoryzacji będzie widoczny interfejs API, który zaakceptuje token odświeżania, sprawdzi jego ważność i zwróci nowy token dostępu.
6) Po wygaśnięciu tokena odświeżania użytkownik zostanie wylogowany.
Daj mi znać, jeśli potrzebujesz więcej szczegółów, mogę również udostępnić kod (Java + Spring boot).
źródło
jwt-autorefresh
Jeśli używasz węzła (React / Redux / Universal JS), możesz zainstalować
npm i -S jwt-autorefresh
.Ta biblioteka planuje odświeżanie tokenów JWT na podstawie obliczonej przez użytkownika liczby sekund przed wygaśnięciem tokena dostępu (na podstawie oświadczenia exp zakodowanego w tokenie). Posiada obszerny zestaw testów i sprawdza całkiem sporo warunków, aby upewnić się, że każdej dziwnej aktywności towarzyszy opisowy komunikat dotyczący błędnych konfiguracji z twojego środowiska.
Pełna implementacja przykładu
Uwaga: Jestem opiekunem
źródło
jwt-autorefresh
go dekoduje, jest wyodrębnienieexp
roszczenia, aby mógł określić, jak daleko jest do zaplanowania następnego odświeżenia.Rozwiązałem ten problem, dodając zmienną do danych tokena:
Ustawiam
expiresIn
opcję na żądany czas, zanim użytkownik będzie zmuszony ponownie się zalogować. Mój ustawiony jest na 30 minut. To musi być większa niż wartośćsoftexp
.Gdy moja aplikacja po stronie klienta wysyła żądanie do interfejsu API serwera (gdzie wymagany jest token, np. Strona listy klientów), serwer sprawdza, czy przesłany token jest nadal ważny, czy nie, w oparciu o jego pierwotną
expiresIn
wartość expiration ( ). Jeśli to nie jest poprawne, serwer zareaguje ze statusem szczególnym dla tego błędu, np.INVALID_TOKEN
.Jeśli token jest nadal ważny na podstawie
expiredIn
wartości, ale już przekroczyłsoftexp
wartość, serwer odpowie osobnym statusem dla tego błędu, np.EXPIRED_TOKEN
:Po stronie klienta, jeśli otrzymał
EXPIRED_TOKEN
odpowiedź, powinien odnowić token automatycznie, wysyłając żądanie odnowienia do serwera. Jest to przezroczyste dla użytkownika i automatycznie obsługiwane przez aplikację kliencką.Metoda odnowienia na serwerze musi sprawdzić, czy token jest nadal ważny:
Serwer odmówi odnowienia tokenów, jeśli nie powiedzie się powyższa metoda.
źródło
Co powiesz na to podejście:
W tym przypadku nie wymagamy dodatkowego punktu końcowego do odświeżenia tokena. Byłby wdzięczny za każdy feedack.
źródło
Obecnie wiele osób decyduje się na zarządzanie sesjami za pomocą JWT, nie zdając sobie sprawy z tego, co rezygnują ze względu na postrzeganą prostotę. Moja odpowiedź dotyczy drugiej części pytań:
JWT są w stanie obsługiwać podstawowe zarządzanie sesjami z pewnymi ograniczeniami. Będąc samoopisującymi się tokenami, nie wymagają one żadnego stanu po stronie serwera. To sprawia, że są atrakcyjne. Na przykład, jeśli usługa nie ma warstwy trwałości, nie musi jej wnosić tylko do zarządzania sesjami.
Jednak bezpaństwowość jest również główną przyczyną ich wad. Ponieważ są wydawane tylko raz ze stałą zawartością i wygaśnięciem, nie można robić rzeczy, które chciałbyś zrobić przy typowej konfiguracji zarządzania sesją.
Mianowicie nie można unieważnić ich na żądanie. Oznacza to, że nie można wdrożyć bezpiecznego wylogowania, ponieważ nie ma możliwości wygaśnięcia już wydanych tokenów. Nie można również wprowadzić limitu czasu bezczynności z tego samego powodu. Jednym z rozwiązań jest utrzymanie czarnej listy, ale wprowadza ona stan.
Napisałem post wyjaśniający te wady bardziej szczegółowo. Aby to wyjaśnić, możesz obejść je, dodając więcej złożoności (sesje przesuwane, tokeny odświeżania itp.)
Jeśli chodzi o inne opcje, jeśli Twoi klienci wchodzą w interakcje z Twoją usługą tylko za pośrednictwem przeglądarki, zdecydowanie zalecamy korzystanie z rozwiązania do zarządzania sesjami opartego na plikach cookie. Opracowałem także metody uwierzytelniania list, które są obecnie szeroko stosowane w Internecie.
źródło