Piszę aplikację internetową w Angular, w której uwierzytelnianie jest obsługiwane przez token JWT, co oznacza, że każde żądanie ma nagłówek „Authentication” ze wszystkimi niezbędnymi informacjami.
Działa to dobrze w przypadku wywołań REST, ale nie rozumiem, jak mam obsługiwać łącza pobierania plików hostowanych na zapleczu (pliki znajdują się na tym samym serwerze, na którym hostowane są usługi sieciowe).
Nie mogę używać zwykłych <a href='...'/>
linków, ponieważ nie mają one żadnego nagłówka, a uwierzytelnianie się nie powiedzie. To samo dotyczy różnych zaklęć window.open(...)
.
Niektóre rozwiązania, o których myślałem:
- Wygeneruj tymczasowe niezabezpieczone łącze pobierania na serwerze
- Przekaż informacje uwierzytelniające jako parametr adresu URL i ręcznie obsłuż sprawę
- Pobierz dane przez XHR i zapisz plik po stronie klienta.
Wszystkie powyższe są mniej niż zadowalające.
1 to rozwiązanie, którego teraz używam. Nie podoba mi się to z dwóch powodów: po pierwsze nie jest to idealne rozwiązanie z punktu widzenia bezpieczeństwa, po drugie działa, ale wymaga sporo pracy, szczególnie na serwerze: aby coś pobrać, muszę zadzwonić do usługi, która generuje nowy "losowy „url, przechowuje go gdzieś (prawdopodobnie w bazie danych) przez jakiś czas i zwraca do klienta. Klient otrzymuje adres URL i używa z nim window.open lub podobnego. Na żądanie nowy adres URL powinien sprawdzić, czy nadal jest ważny, a następnie zwrócić dane.
2 wydaje się co najmniej tyle pracy.
3 wydaje się dużo pracy, nawet przy użyciu dostępnych bibliotek i wiele potencjalnych problemów. (Musiałbym zapewnić własny pasek stanu pobierania, załadować cały plik do pamięci, a następnie poprosić użytkownika o zapisanie pliku lokalnie).
Zadanie wydaje się jednak dość podstawowe, więc zastanawiam się, czy jest coś znacznie prostszego, czego mógłbym użyć.
Niekoniecznie szukam rozwiązania „po kątach”. Zwykły Javascript byłby w porządku.
źródło
Odpowiedzi:
Oto sposób, aby pobrać go na kliencie za pomocą atrybutu pobierania , pobranie informacji API i URL.createObjectURL . Pobrałbyś plik za pomocą tokena JWT, przekonwertowałbyś ładunek na obiekt blob, umieścił obiekt blob w objectURL, ustawił źródło tagu kotwicy na ten objectURL i kliknął ten objectURL w javascript.
Wartością
download
atrybutu będzie ostateczna nazwa pliku. Jeśli chcesz, możesz wydobyć zamierzoną nazwę pliku z nagłówka odpowiedzi dyspozycji dyspozycji treści, jak opisano w innych odpowiedziach .źródło
Technika
Na podstawie rady Matiasa Wołoskiego z Auth0, znanego ewangelisty JWT, rozwiązałem go, generując podpisaną prośbę z Hawkiem .
Cytując Woloskiego:
Tutaj masz przykład tej techniki, używanej do linków aktywacyjnych.
zaplecze
Stworzyłem API do podpisywania moich adresów URL pobierania:
Żądanie:
Odpowiedź:
Za pomocą podpisanego adresu URL możemy pobrać plik
Żądanie:
Odpowiedź:
frontend (przez jojoyuji )
W ten sposób możesz to wszystko zrobić jednym kliknięciem użytkownika:
źródło
Alternatywą dla istniejących już podejść „fetch / createObjectURL” i „download-token” jest standardowy formularz POST, który jest przeznaczony dla nowego okna . Gdy przeglądarka odczyta nagłówek załącznika w odpowiedzi serwera, zamknie nową kartę i rozpocznie pobieranie. To samo podejście działa również dobrze przy wyświetlaniu zasobu, takiego jak plik PDF, w nowej karcie.
Zapewnia to lepszą obsługę starszych przeglądarek i pozwala uniknąć konieczności zarządzania nowym typem tokena. Zapewni to również lepszą obsługę długoterminową niż podstawowe uwierzytelnianie adresu URL, ponieważ obsługa nazwy użytkownika / hasła w adresie URL jest usuwana przez przeglądarki .
Po stronie klienta używamy,
target="_blank"
aby uniknąć nawigacji nawet w przypadkach awarii, co jest szczególnie ważne w przypadku SPA (aplikacji jednostronicowych).Głównym zastrzeżeniem jest to, że weryfikacja JWT po stronie serwera musi pobrać token z danych POST, a nie z nagłówka . Jeśli struktura zarządza dostępem do programów obsługi tras automatycznie przy użyciu nagłówka uwierzytelniania, może być konieczne oznaczenie procedury obsługi jako nieuwierzytelnionej / anonimowej, aby można było ręcznie sprawdzić poprawność tokena JWT w celu zapewnienia właściwej autoryzacji.
Formularz może być dynamicznie tworzony i natychmiast niszczony, aby został odpowiednio wyczyszczony (uwaga: można to zrobić w zwykłym JS, ale dla przejrzystości zastosowano tutaj JQuery) -
Po prostu dodaj wszelkie dodatkowe dane, które musisz przesłać jako ukryte dane wejściowe i upewnij się, że zostały dołączone do formularza.
źródło
Generowałbym tokeny do pobrania.
W ramach angular wyślij uwierzytelnione żądanie uzyskania tymczasowego tokena (powiedzmy na godzinę), a następnie dodaj go do adresu URL jako parametr get. W ten sposób możesz pobierać pliki w dowolny sposób (window.open ...)
źródło
Dodatkowe rozwiązanie: użycie podstawowego uwierzytelnienia. Chociaż wymaga to trochę pracy na zapleczu, tokeny nie będą widoczne w dziennikach i nie będzie trzeba zaimplementować podpisywania adresów URL.
Strona klienta
Przykładowy adres URL może wyglądać tak:
http://jwt:<user jwt token>@some.url/file/35/download
Przykład z fałszywym tokenem:
http://jwt:eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIwIiwibmFtZSI6IiIsImlhdCI6MH0.KsKmQOZM-jcy4l_7NFsv1lWfpH8ofniVCv75ZRQrWno@some.url/file/35/download
Następnie możesz to włożyć
<a href="...">
lubwindow.open("...")
- przeglądarka zajmie się resztą.Po stronie serwera
Wdrożenie tutaj zależy od Ciebie i zależy od konfiguracji serwera - nie różni się zbytnio od użycia
?token=
parametru zapytania.Korzystając z Laravel, poszedłem na łatwą ścieżkę i przekształciłem podstawowe hasło uwierzytelniające w
Authorization: Bearer <...>
nagłówek JWT , pozwalając normalnemu oprogramowaniu pośredniczącemu uwierzytelniania zająć się resztą:źródło