Request Filter mit Alice

Requests in mehreren Schritten behandeln

  • Requests werden in der Regel von mehreren Handlern hintereinander behandeltDrei Filter und ein Handler, die nacheinander ausgeführt werden
    • entspricht meist verschiedenen logischen Schichten der App
    • z.B. CSRF Schutz → Sitzung überprüfen → Autorisierung → Applikationslogik
  • Die Go Library Alice macht das Verketten von Handlern einfach
    • Handler müssen mit einer Konstruktorfunktion mit vorgegebener Signatur erzeugt werden können:

  • Handler bearbeiten Request: alles ok → nächster Handler in der Kette, sonst Abbruch der Request-Bearbeitung
    • Alice sorgt dafür, dass die Handler in der richtigen Reihenfolge und mit dem passenden nächsten Handler konstruiert werden
    • So können Ketten von Handlern einfach angelegt werden

Auf der Github Seite von Alice ist beschrieben, wie auch Handler mit mehreren Parametern in der Konstruktorfunktion angepasst werden können.

Eigene Request Filter implementieren

Mit wenig Aufwand können eigene Filter implementiert werden. Zuerst brauchen wir ein bischen Infrastruktur-Code:

12
Der abstrakte Funktionstyp chainfunc definiert die Signatur für den Filter-Algorithmus. Der 3. Parameter vom Typ interface{} macht die Filterfunktion flexibel, sie kann einen beliebigen weiteren Parameter bekommen.
15-18
Die struct chainableHandler speichert eine Filterfunktion und den Link zum nächsten Handler in der Kette.
21-25
Die struct chainableHandler bekommt eine Methode ServeHTTP(…) und implementiert damit das http.Handler Interface. ServeHTTP ruft den nächsten Handler nur dann auf, wenn die Filterfunktion true liefert.
  • Damit ist die Basis für eigene Filter in der Alice Filterkette vorhanden.
Einfaches Beispiel: ein Request Logger

Die Implementierung eines einfachen Filters besteht mit der oben beschriebenen Infrastruktur aus zwei Schritten:

  1. Filterfunktion implementieren (als Beispiel logRequest(...) ).
  2. Public Konstruktorfunktion RequestLogger anlegen. Diese bettet die Filterfunktion in die struct chainableHandler ein. In Zeile 59 ist ein typecast auf den Funktionstyp chainfunc notwendig.

Session Checker Filter

Dieser Filter überprüft, ob eine Gorilla Session vorhanden ist. Der Aufbau ist weitgehend analog zum Logging Filter, jedoch treten einige Fälle auf, in denen false zurückgegeben wird. Damit wird der Aufruf der weiteren Handler in der Filterkette unterbunden. In Zeilen 41 und 49 erkennt man, wie der Filter in den Fluss der Webseiten durch ein Redirect eingreifen kann, wenn nach einem Server-Neustart eine ungültige Sitzung entdeckt wird.

Aufbau von Filtern mit zusätzlichen Parametern

Häufig benötigt man Filterfunktionen, die noch einen zusätzlichen Parameter besitzen. Da Alice nicht vorsieht, dass ein Filter noch weitere Parameter im Konstruktor bekommt, können wir eine eigene Filterfunktion für jeden sinnvollen Wert dieses Parameters anlegen. Das geht natürlich nur, wenn es einen relativ kleinen Wertebereich für diesen Parameter gibt. Die Hilfsfunktion makeFilter(...)  macht die Konstruktion derartiger Filter einfacher, indem sie einer Funktion mit drei Parametern einen Filter mit den für Alice notwendigen 2 Parametern erzeugt.

Wenn die Filterfunktion also weitere Parameter besitzt, müssen diese jeweils für einen bestimmten Wert festgehalten werden. Dadurch wird die Anzahl der Parameter reduziert, wir erhalten eine Funktion vom Typ filter. In der funktionalen Programmierung wird das nach dem Mathematiker Haskel Curry als Currying bezeichnet. Es gibt also ein oder zwei weitere Schritte:

  1. Eine „Currying“-Funktion implementieren, wenn makeFilter nicht passt.
  2. Für jeden sinnvollen Wert der Zusatzparameter eine Konstruktorfunktion für den Filter-Handler anlegen. Das wird weiter unten am Beispiel des Authorization Filter demonstriert.

89-90
makeFilter ist eine Funktion, die als Parameter eine Funktion
f func(http.ResponseWriter, *http.Request, interface{}) bool  mit drei Parametern und Rückgabetyp bool sowie ein Interface mask interface{}  besitzt und eine Funktion vom Typ filter  zurückgibt.
92
Die anonyme Funktion, die zurückgegeben wird, ruft in ihrer Implementierung die als Parameter übergebene Funktion f mit dem 3. Parameter mask auf, der damit festgehalten wird.
Authorization Filter

Dieser Filter verwendet die in der Session abgespeicherten Informationen über den aktuellen User, um seine Zugriffsrechte auf eine URL zu überprüfen.Das Beispiel verwendet ein einfaches Rollenmodell zur Rechteverwaltung. Die eigentliche Filterfunktion ist checkAuth(...) .

Wie zu erkennen ist, braucht diese Funktion noch einen zusätzlichen Parameter (Z. 73), der als Maskierung für die role Variable dient (Z. 81). Mit makeFilter(...)  (s.o.) wird daraus ein Filter mit den für Alice notwendigen 2 Parametern erzeugt.

Damit lassen sich jetzt sehr einfach die Autorisierungsfilter für die fünf verschiedenen Rollen erzeugen.

99, 108, 117, 126, 135
In diesen Zeilen wird mit makeFilter eine Filterfunktion aus der Funktion checkAuth() erzeugt. Dabei wird jeweils eine Konstante als 3. Parameter an checkAuth übergeben.
97-103
AuthAny() implementiert damit eine Handlerfunktion für die Rolle, die durch die Konstante model.U_ALL  vorgegeben ist.
106-112, 115-121, 124-130, 133-139
Entsprechend werden auch die Filterfunktionen für die anderen definierten Rollen implementiert.

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.