Ich schreibe einen REST - Client in Java mit dem HttpCLient. Die REST - API, auf die ich zugreife, benötigt für jede REST - Aktion ein Auth-Token. Dieses Token ist 24 Stunden gültig.
Die Art und Weise, wie ich dies jetzt handle, ist das Aufrufen einer "getAuth()
" -Methode jedes Mal, wenn ich einen REST - Aufruf machen muss, der auf dem Auth-Server wie ein Overhead erscheint.
Wie kann ich dieses Authentifizierungs-Token bequem speichern und seinen Lebenszyklus verwalten? Gibt es dokumentierte Best Practices?
Ich dachte an die folgende Lösung
public class MySession {
String user;
String pass;
public MySession(String user, String pass) {
this.user = user;
this.pass = pass;
}
public getAuth() {
//user user, pass to get auth token
}
}
und übergeben Sie dann das Sessions-Objekt an eine Klasse, die das Token benötigt. Wenn das Token abgelaufen ist, rufen Sie diese Methode einfach erneut auf
Der Kürze halber nehme ich an, Sie nennen einen Endpunkt, den Sie nicht ändern können. Wie Sie implementieren sollten, hängt stark davon ab, ob das Token app- oder benutzerbasiert ist (ein Token für alle Benutzer einer gemeinsam genutzten Anwendungsinstanz oder ein Token pro Benutzer).
Wenn es sich um ein Authentifizierungs-Token für die gesamte App handelt:
Wenn es ein Token pro Benutzer ist:
Ich gehe davon aus, dass Sie OAuth zur Autorisierung verwenden. Ob Sie JWT oder andere Token verwenden, ist für diese Situation unerheblich.
Bei der Autorisierung erhalten Sie einen access_token
mit Ablaufdatum und je nach Art der von Ihnen beantragten Art (Client-Berechtigungsnachweis, Autorisierungscode, implizit, Ressourcenbesitzer) einen refresh_token
.
Der Client sollte den access_token
und den Ablauf beibehalten. Das Refresh_token muss, falls es ausgegeben wird, geheim gehalten werden (achten Sie darauf, dass Sie die richtige Zuteilung für Ihren Anwendungsfall verwenden).
Bei nachfolgenden Aufrufen sollte Ihr Client bei jedem Anruf keine neuen Token anfordern, sondern den gespeicherten access_token
verwenden.
Wenn die API anfängt, 401 Unauthorized
zurückzugeben, ist der access_token
wahrscheinlich abgelaufen. Ihr Client sollte versuchen, den access_token
mit dem refresh_token
zu aktualisieren, falls Sie einen haben.
Wenn Sie keinen refresh_token
haben oder die Aktualisierungsanforderung ebenfalls fehlgeschlagen ist, da der refresh_token
nicht mehr gültig ist, können Sie einen neuen Autorisierungsablauf durchführen.
Sie können die Ablaufzeit als Anhaltspunkt verwenden, um zu wissen, wann Sie einen neuen access_token
erhalten, entweder durch Aktualisierung oder durch einen neuen vollständigen Autorisierungsfluss. Dadurch wird der 401 Unauthorized
vermieden. In jedem Fall sollte Ihr Client über eine Rückfallrichtlinie verfügen, wenn diese Antwort empfangen wird, nachdem für einige Anrufe ein gültiger access_token
verwendet wurde.
Wenn Sie sich Sorgen über zu viele Zugriffe auf die Datenbank machen, gehe ich davon aus, dass es eine Menge Webaktivitäten gibt.
Ich würde die Verwendung von Session in Ihrem Fall nicht empfehlen, sondern das Token in einem Cookie auf dem Client speichern.
In einer Umgebung mit hohem Datenaufkommen (was ich für Ihre voraussetze) kann die Verwendung von Session viel Serverspeicher beanspruchen, und die Skalierbarkeit kann ebenfalls ein Problem sein, da Sitzungen innerhalb eines Clusters synchron gehalten werden müssen.
Wie @ Cássio Mazzochi Molin auch erwähnt hat, können Sie einen In-Memory-Cache verwenden, um benutzerspezifische Daten und Token zu speichern. Dadurch werden die Zugriffe auf die Datenbank reduziert und Sie können die Anwendung bei Bedarf auch einfacher skalieren.
Ich schlage vor, folgendes Szenario zu verwenden:
1) Rufen Sie zuerst auth(username, password)
rest api auf, um das Auth-Token abzurufen. Wenn die angegebenen Berechtigungsnachweise in Ordnung sind, senden Sie das Auth-Cookie mit dem HTTP 200-Antwortcode an den Client zurück.
2) Dann können Sie Protected Rest Apis aufrufen. Sie müssen jedes Mal ein Authentifizierungs-Cookie mit Ihrer Anfrage senden.
3) Der Servlet-Filter (oder ähnliches) überprüft jede eingehende Anforderung und validiert das Token. Wenn das Token gültig ist, wird die Anforderung an die Rest-Methode weitergeleitet, andernfalls müssen Sie eine http 401/403-Antwort generieren.
Ich schlage vor, dass Sie keine eigene Authentifizierungsschicht schreiben. Anstelle eines vorhandenen installieren und verwenden. Ich schlage vor, dass Sie OpenAM . Es ist ein hervorragendes Open Source Access Management System.
Ich empfehle Ihnen außerdem, die Sitzung auf der Serverseite nicht zu Authentifizierungszwecken zu öffnen. Wenn Sie 10 Clients haben, müssen 10 Sitzungen vom Server verwaltet werden. Es ist kein großes Problem. Wenn Sie jedoch 100 oder 1000 oder Millionen verschiedene Clients haben, benötigen Sie mehr Speicher zum Speichern von Sitzungen auf dem Server.
Sie sollten JsonWebToken (kurz JWT) für diese Art von Sachen verwenden. JWT verfügt über eine integrierte Unterstützung zum Festlegen des Ablaufdatums. Es gibt viele Bibliotheken, die diese Methode verwenden, und Sie können mehr lesen here
Es gibt derzeit 4 Java-Implementierungen, und alle können prüfen, ob das Token noch gültig ist (Exp-Check)
Wenn ich das richtig verstehe, verwenden Sie dasselbe Token für alle Ihre Anforderungen (dh solange Ihre App läuft und Sie die Token aktualisieren, sollten Sie in Ordnung sein. Ich hatte buchstäblich das gleiche Problem und dies ist der Fall Wie habe ich das Problem gelöst? Ich habe eine Singleton-Klasse, die beim Start der App einmalig initialisiert wird und das Token aktualisiert, wenn es ungültig gemacht wird. Ich verwende C #, Asp.NET MVC5 und AutoFac für DI, bin aber sicher Sie können dasselbe mit Java und Spring tun.
Sie können einen Manager erstellen und das Authentifizierungscookie während der Anmeldung in Thread Local wie dem folgenden Code speichern. Sie können den Cookie von getAuth()
erhalten, solange der Thread läuft.
public class Manager {
private static final ThreadLocal<String> SECURITY_CONTEXT = new ThreadLocal<>();
public static void setAuth(String auth) {
SECURITY_CONTEXT.set(auth);
}
public static String getAuth() {
return SECURITY_CONTEXT.get();
}
public static void clear(){
SECURITY_CONTEXT.remove();
}
}
Der De-facto-Standard implementiert keine eigene Lösung (Grundregel in der Sicherheit: Implementiere keine eigenen Sachen!), Sondern verwende die De-facto-Standardlösung, nämlich JSON Web Tokens .
Dokumentation auf der Site, aber die Grundidee ist, dass Sie nur einen Wert speichern müssen (den privaten Schlüssel des Servers), und dann können Sie jeden ursprünglich vom Server ausgestellten Anspruch überprüfen (der in Ihrem Fall eine Ablaufzeit enthält). .
Verwenden Sie json Web Token, um Informationen zwischen zwei Clients auszutauschen. Das Token ist nur für die Dauer von 24 Stunden aktiv. Danach werden alle darauffolgenden Aufrufe im Header zurückgewiesen.