Entw.: RESTServer-Entwicklung (01)
Projektstruktur
Die IDE der Entwicklungumgebung von Embarcadero bietet die Möglichkeit, basiert auf dem gleichen Source-Stand, gleichzeitig einen StandAlone-Server sowie eine ISAPI-Version für den Internet Information Server (IIS) zu entwickeln.
Automatische Parallelentwicklung
Dies ist in der Praxis vom grossen Preisvorteil. Es lassen sich so Entwicklungs- und Testzeiten einspaaren, da das Arbeiten mit dem StandAlone-Server während der Entwicklungphase einfach besser zu handhaben ist. Aus Entwicklersicht ist Client und Server eine Einheit. Z.B. wird eine neue REST-Methode erstellt, so wird für den Client automatisch der entsprechende Client-Source erzeugt. Jede neue oder geänderte REST-Methode lässt sich über den sogenannten Server Function Invoker sofort schnell austesten.
Security
Im Zeitalter von Weiterleitungen und Loadbalancing ist oft eine eigene Authentifizierung zu implementieren,
um eine eindeutige Identifizierung von Client und Benutzer durch den Server-Prozess sicher zustellen.
Das Authentifizierungsverfahren und die Verwendung der anderen Sicherungsmassnahmen von DataSnap kann zusätzlich hinzugeschaltet werden.
Das hier vorgestellte Authentifizierungsverfahren basiert auf folgende Implementierungsdetails:
- Die verwendete User-SessionId (USID) ist nicht interpretierbar. Jede Client-Anfrage benötigt eine gültige USID. Eine gültige USID erhält der Client nach einer erfolgreichen Authentifizierung.
- Die Authentifizierung erfolgt mit 4 Parametern: Benutzername, Passwort, Mandant, Rolle. Zwischen Benutzernamen, Mandant und Rolle besteht eine Datenrelation (Dreiecksbeziehung)
- IP-Adressen werden überwacht. Verwaltet werden Positiv- und Negativlisten von IP-Adressen, so dass sehr schnell auf unerlaubte Zugriffe durch die Verwaltung reagiert werden kann.
- Bei automatisierten Angriffen werden die Remote-IP-Adressen automatisch gesperrt. Dabei ist die Sperrzeit temporär und die Dauer richtet sich nach der Anzahl von Login-Versuchen. Temporäre Sperren lassen sich jederzeit in Permanentsperren überführen.
- Alle Anfragen von gesperrten IP-Adressen werden auf eine Null-Methode umgeleitet. Dadurch wird das Gesamtsystem des Servers entlastet.
Folgender Source zeigt hierzu die Implementierung bei der HTTP-Zugriffsart GET:
procedure THermesWebModule.DSHTTPWebDispatcherRESTMethodNameMapGET( Sender: TObject; const ClassCtx, MethodCtx: string; out DSMethodName: string); var l_iBeg: Integer; l_sPar, l_sStr: String; l_lDoExNullMethode: Boolean; begin l_lDoExNullMethode := False; DSMethodName := Format('%s.%s', [ClassCtx, MethodCtx]); CodeSite.Send('GET Methode: ' + DSMethodName); if not DMMainServerModule.IsValidRemoteAddr(Request.RemoteAddr) then begin l_lDoExNullMethode := True; CodeSite.Send(' Invalid RemoteAddr' + Request.RemoteAddr); end; if MethodCtx = 'Authentification' then begin if not DMMainServerModule.IsExplizitValidRemoteAddr(Request.RemoteAddr) then begin l_sStr := String(Request.PathTranslated); l_iBeg := Pos(MethodCtx,l_sStr); l_sPar := Copy(l_sStr,l_iBeg+Length(MethodCtx)+1,999); if DMMainServerModule.CheckIfTooManyLogins(Request.RemoteAddr, l_sPar) then begin l_lDoExNullMethode := True; CodeSite.Send(' Too many logins by RemoteAddr: ' + Request.RemoteAddr + '; TS: ' + DateTimeToStr(Now)); end; end; end; if l_lDoExNullMethode then begin DSMethodName := 'TDMHermesAdminMethods.NullMethode'; CodeSite.Send(' Execute NullMethode'); end; end;
Auch für die HTTP-Zugriffsart PUT gibt es eine ähnliche Implementierung.
StandAlone-Server
In der Entwicklungs- und Testphase ist der StandAlone-Server von DataSnap massgebend. Es handelt sich um eine einfache Exe-Datei für einem Windows-Rechner. Nach dem Programmstart erscheint nachfolgendes Fenster.
StandAlone-Server
Aktivieren lässt sich der eigentliche RESTServer durch dem Button Starten. Die Client-Seite lässt sich ebenfalls aus diesem Fenster durch dem Buttom Browser öffnen starten. Im geöffneten Browser erscheint die Startseite der WebApp. Zusätzlich erscheint beim lokalen Start ein Link auf den sogenannten Server Function Invoker.
Lokaler Test mit Server Function Invoker
Für den schnellen Test bietet DataSnap die Möglichkeit, neue bzw. geänderte REST-Methoden sofort zu testen. Folgender Source zeigt die Deklarationen von einigen implementierten REST-Methoden.
type {$MethodInfo ON} TDMHermesDataLists = class(TDSServerModule) private { Private declarations } function GetJSONObjectMaengelGefahrgutwagenHeader1(const Farbe, Text1: String): TJSONObject; function GetJSONObjectMaengelGefahrgutwagenHeader2(const Farbe, Text1, Text2, Text3, Text4, Text5: String): TJSONObject; function GetJSONObjectMaengelGefahrgutwagenLine(const Farbe: String; const AnzInGroup: Integer; const Text1, Ladestelle: String; AnzKontrolliert,AnzKleineMaengel,AnzGrosseMaengel: Integer): TJSONObject; public { Public declarations } function WagenlisteAktuelleRAs( // Liefert eine Wagenliste von allen aktiven Rangierauftraegen const USID: String; const SortierungNachZeit: Boolean; // True: Sortierung nach Zeit; False: Sortierung nach Wagennummer const RowNoBeg, RowNoEnd: Integer ): TJSONObject; function WagenlisteRAs( // Liefert eine Wagenliste von Rangierauftraegen const USID: String; const Wagennummer: String; // <Leer>, '*' oder konkrete Wagennummer const Beladen: Boolean; // True oder False const Ladegut: String; // <Leer>, '*' oder z.B. '11', '07 - Polyester' const ZugestelltVon: String; // <Leer>, '*' oder z.B. '2101', '2101 - Gleis xyz' const AbgeholtNach: String; // <Leer>, '*' oder z.B. '2101', '2101 - Gleis xyz' const SortierungNachZeit: Boolean; // True: Sortierung nach Zeit; False: Sortierung nach Wagennummer const VonDatum, BisDatum: TDateTime; const RowNoBeg, RowNoEnd: Integer ): TJSONObject; function WagenlisteBestand( // Liefert eine Liste des aktuellen Wagenbestands const USID: String; const Wagennummer: String; // <Leer>, '*' oder konkrete Wagennummer const Beladen: Boolean; // True oder False const Ladegut: String; // <Leer>, '*' oder z.B. '11', '07 - Polyester' const Standort: String; // <Leer>, '*' oder z.B. '2101', '2101 - Gleis xyz' const SortierungNachStandort: Boolean; // True: Sortierung nach Wagenstandort; False: Sortierung nach Wagennummer const RowNoBeg, RowNoEnd: Integer ): TJSONObject; function StatistikMaengelGefahrgutwagen( // Liefert eine Aufstellung ueber Maengel an Gefahrgutwagen const USID: String; const VonDatum, BisDatum: TDateTime ): TJSONObject; function StatistikAusgang( // Liefert eine Aufstellung der Ausgaenge in einem bestimmten Zeitraum const USID: String; const Beladen: Boolean; // True oder False const Ladegut: String; // <Leer>, '*' oder z.B. '11', '07 - Polyester' const EmpfaengerGleis: String; // <Leer>, '*' oder z.B. '2101', '2101 - Gleis xyz' const VonDatum, BisDatum: TDateTime ): TJSONObject; function StatistikEingang( // Liefert eine Aufstellung der Eingaenge in einem bestimmten Zeitraum const USID: String; const Beladen: Boolean; // True oder False const Ladegut: String; // <Leer>, '*' oder z.B. '11', '07 - Polyester' const EmpfaengerGleis: String; // <Leer>, '*' oder z.B. '2101', '2101 - Gleis xyz' const VonDatum, BisDatum: TDateTime ): TJSONObject; end; {$MethodInfo OFF}
Beim Start des RESTServers werden mit Hilfe von Reflexion die JavaScript-Aufrufe für den Client erzeugt. Diese Aufrufe werden werden vom Server Function Invoker für den lokalen Test verwendet.
Lokaler Test
Das rechte Bild zeigt den Browser mit der Oberfläche des Server Function Invoker's.
Copyright © 26.03.2011 hadv.de. All Rights Reserved.