Ich schreibe eine Webanwendung in Angular, in der die Authentifizierung von einem JWT-Token verwaltet wird. Dies bedeutet, dass jede Anforderung einen "Authentifizierungs" -Header mit allen erforderlichen Informationen enthält.
Dies funktioniert gut für REST-Aufrufe, aber ich verstehe nicht, wie ich mit Download-Links für im Backend gehostete Dateien umgehen soll (die Dateien befinden sich auf demselben Server, auf dem die Webservices gehostet werden).
Ich kann keine regulären <a href='...'/>
Links verwenden, da diese keinen Header enthalten und die Authentifizierung fehlschlägt. Gleiches gilt für die verschiedenen Beschwörungsformeln von window.open(...)
.
Einige Lösungen, an die ich gedacht habe:
- Generieren Sie einen temporären ungesicherten Download-Link auf dem Server
- Übergeben Sie die Authentifizierungsinformationen als URL-Parameter und behandeln Sie den Fall manuell
- Holen Sie sich die Daten über XHR und speichern Sie die Datei clientseitig.
Alle oben genannten sind weniger als zufriedenstellend.
1 ist die Lösung, die ich gerade verwende. Ich mag es aus zwei Gründen nicht: Erstens ist es in Bezug auf die Sicherheit nicht ideal, zweitens funktioniert es, aber es erfordert ziemlich viel Arbeit, insbesondere auf dem Server: Um etwas herunterzuladen, muss ich einen Dienst aufrufen, der einen neuen "Zufall" generiert "url, speichert es für einige Zeit irgendwo (möglicherweise in der Datenbank) und gibt es an den Client zurück. Der Client erhält die URL und verwendet window.open oder ähnliches. Auf Anfrage sollte die neue URL prüfen, ob sie noch gültig ist, und dann die Daten zurückgeben.
2 scheint mindestens so viel Arbeit.
3 scheint viel Arbeit zu sein, selbst wenn verfügbare Bibliotheken verwendet werden, und viele potenzielle Probleme. (Ich müsste meine eigene Download-Statusleiste bereitstellen, die gesamte Datei in den Speicher laden und dann den Benutzer bitten, die Datei lokal zu speichern.)
Die Aufgabe scheint jedoch ziemlich einfach zu sein, daher frage ich mich, ob es etwas viel Einfacheres gibt, das ich verwenden kann.
Ich bin nicht unbedingt auf der Suche nach einer Lösung "the Angular way". Normales Javascript wäre in Ordnung.
quelle
Antworten:
Hier ist eine Möglichkeit, es mit dem Download-Attribut , der Fetch-API und URL.createObjectURL auf den Client herunterzuladen . Sie würden die Datei mit Ihrem JWT abrufen, die Nutzdaten in einen Blob konvertieren, den Blob in eine objectURL einfügen, die Quelle eines Ankertags auf diese objectURL setzen und auf diese objectURL in Javascript klicken.
Der Wert des
download
Attributs ist der eventuelle Dateiname. Falls gewünscht, können Sie einen beabsichtigten Dateinamen aus dem Header der Inhaltsdisposition abrufen, wie in anderen Antworten beschrieben .quelle
Technik
Basierend auf diesem Rat von Matias Woloski von Auth0, einem bekannten JWT-Evangelisten, löste ich ihn, indem ich eine unterschriebene Anfrage mit Hawk generierte .
Woloski zitieren:
Hier haben Sie ein Beispiel für diese Technik, die für Aktivierungslinks verwendet wird.
Backend
Ich habe eine API erstellt, um meine Download-URLs zu signieren:
Anfrage:
Antwort:
Mit einer signierten URL können wir die Datei erhalten
Anfrage:
Antwort:
Frontend (von Jojoyuji )
Auf diese Weise können Sie alles mit einem einzigen Benutzerklick erledigen:
quelle
Eine Alternative zu den bereits erwähnten Ansätzen "fetch / createObjectURL" und "download-token" ist ein Standard- Formular-POST, der auf ein neues Fenster abzielt . Sobald der Browser den Anhangskopf in der Serverantwort liest, schließt er die neue Registerkarte und beginnt mit dem Download. Dieser Ansatz eignet sich auch gut zum Anzeigen einer Ressource wie einer PDF-Datei in einem neuen Tab.
Dies bietet eine bessere Unterstützung für ältere Browser und vermeidet die Verwaltung eines neuen Tokentyps. Dies hat auch langfristig eine bessere Unterstützung als die grundlegende Authentifizierung der URL, da die Unterstützung für Benutzername / Passwort in der URL von Browsern entfernt wird .
Auf der Clientseite
target="_blank"
vermeiden wir die Navigation auch in Fehlerfällen, was besonders für SPAs (Single Page Apps) wichtig ist.Die größte Einschränkung besteht darin, dass die serverseitige JWT-Validierung das Token aus den POST-Daten und nicht aus dem Header abrufen muss . Wenn Ihr Framework den Zugriff auf Routenhandler mithilfe des Authentifizierungsheaders automatisch verwaltet, müssen Sie Ihren Handler möglicherweise als nicht authentifiziert / anonym markieren, damit Sie die JWT manuell validieren können, um eine ordnungsgemäße Autorisierung sicherzustellen.
Das Formular kann dynamisch erstellt und sofort zerstört werden, damit es ordnungsgemäß bereinigt wird (Hinweis: Dies kann in einfachem JS erfolgen, JQuery wird hier jedoch aus Gründen der Übersichtlichkeit verwendet).
Fügen Sie einfach alle zusätzlichen Daten hinzu, die Sie als versteckte Eingaben übermitteln müssen, und stellen Sie sicher, dass sie an das Formular angehängt werden.
quelle
Ich würde Token zum Download generieren.
Stellen Sie innerhalb von Angular eine authentifizierte Anforderung, um ein temporäres Token zu erhalten (z. B. eine Stunde), und fügen Sie es dann der URL als get-Parameter hinzu. Auf diese Weise können Sie Dateien nach Belieben herunterladen (window.open ...)
quelle
Eine zusätzliche Lösung: Verwendung der Basisauthentifizierung. Obwohl das Backend ein wenig Arbeit erfordert, werden Token in Protokollen nicht angezeigt und es muss keine URL-Signatur implementiert werden.
Client-Seite
Eine Beispiel-URL könnte sein:
http://jwt:<user jwt token>@some.url/file/35/download
Beispiel mit Dummy-Token:
http://jwt:eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIwIiwibmFtZSI6IiIsImlhdCI6MH0.KsKmQOZM-jcy4l_7NFsv1lWfpH8ofniVCv75ZRQrWno@some.url/file/35/download
Sie können dies dann einschieben
<a href="...">
oderwindow.open("...")
- der Browser erledigt den Rest.Serverseite
Die Implementierung hier liegt bei Ihnen und hängt von Ihrem Server-Setup ab - es unterscheidet sich nicht allzu sehr von der Verwendung des
?token=
Abfrageparameters.Mit Laravel ging ich den einfachen Weg und wandelte das grundlegende Authentifizierungskennwort in den JWT-
Authorization: Bearer <...>
Header um, sodass die normale Authentifizierungs-Middleware den Rest erledigte:quelle