WklGatewayClient – VBA-Klasse für den Datendienst
WklGatewayClient ruft die Befehle der Verwaltungsschnittstelle des Datendienstes (Wkl.Data.Gateway)
aus VBA auf: Schlüssel ausstellen, zweiten Faktor einrichten, Verbindung prüfen und weitere. Sie
ist zugleich die Vorlage für jede VBA-Anwendung, die mit dem Dienst über HTTP spricht.
Listen – Datenquellen, Regeln, Personen, Schlüssel – liest und bearbeitet eine Access-Anwendung als verknüpfte Tabellen über den ODBC-Treiber des Dienstes. Was ein Geheimnis zurückgibt oder über eine Zeile hinaus wirkt, ist ein Befehl; dafür ist diese Klasse da. Die Mengen und Befehle selbst beschreibt die HTTP: Verwaltung (Referenz) (Dokumentation des Datendienstes).
Unterstützte Umgebung
Microsoft Access aus Microsoft 365 in 32 und 64 Bit, in einer ACCDB, einer ACCDE und in der Access-Runtime. Die Verwaltungsanwendung ruft ihre Befehle über diese Klasse auf.
Voraussetzungen
| Voraussetzung | Wozu |
|---|---|
| Microsoft Access aus Microsoft 365, 32 oder 64 Bit | siehe Unterstützte Umgebung |
Verweis WKL Office JSON 1.1 (registrierte Wkl.Office.JSON.dll der Office-Bitbreite; bis Release 1.0.3 WKL Access JSON 1.0 mit Wkl.Access.JSON.dll) | Antworten als JDoc, Anfragen bauen |
WinHTTP (WinHttp.WinHttpRequest.5.1, Teil von Windows) | HTTP; spät gebunden, kein Verweis |
Klassenmodul StringBuilder (StringBuilder.cls) | Texte aus vielen Teilen (Kopfzeilen, Base64, URL-Kodierung) |
Ein Dienst mit Verwaltungsspeicher und eine Person mit dem Recht admin | Die Befehle |
Einbindung
- Im VBA-Editor Datei → Datei importieren: die Klassenmodule
WklGatewayClient.clsundStringBuilder.cls, bei Bedarf die BeispieleWklGatewayClientExamples.bas. Hat das Projekt schon ein KlassenmodulStringBuilder, entfällt dessen Import. Die Dateien liegen im Ordnervba-classder Lieferung: in der Freigabe bzw. im ZIP neben dem Starter, nach der Installation im ProgrammordnerWKL\GatewayManager. - Extras → Verweise: „WKL Office JSON 1.1“ ankreuzen (bis Release 1.0.3 „WKL Access JSON 1.0“).
- Kompilieren (Debuggen → Kompilieren).
Die Dateien liegen im Format, das der VBA-Editor exportiert und importiert. LoadFromText von
Access erwartet für ein Klassenmodul ein anderes Format (ohne VERSION 1.0 CLASS … END und ohne
VB_Name); mit dem Exportformat legt es ein Standardmodul an. Für LoadFromText entfernen Sie
deshalb den Block von VERSION 1.0 CLASS bis zur ersten Zeile END und die Zeile
Attribute VB_Name = …; die Datei beginnt dann mit den Zeilen Attribute VB_GlobalNameSpace ….
Verwendung
Eine Instanz für die ganze Sitzung der Anwendung: Sie hält die Sitzung des zweiten Faktors.
Private m_Client As WklGatewayClient Public Function Gateway() As WklGatewayClient If m_Client Is Nothing Then Set m_Client = New WklGatewayClient m_Client.BaseUrl = "https://daten.example.com" m_Client.SignIn = gwPersonalKey ' Key from Windows Credential Manager End If Set Gateway = m_Client End Function Sub Example() Dim answer As JDoc On Error GoTo ErrorHandler Set answer = Gateway().IssueKey("Erika Muster", Label:="Laptop", Delivery:="link") Debug.Print answer.GetString("$.link") GoTo FinalHandler ErrorHandler: MsgBox Err.Description, vbExclamation ' Error numbers: see section "Fehler" Resume FinalHandler FinalHandler: Set answer = Nothing End Sub
WklGatewayClientExamples.bas enthält jeden Befehl einmal, mit Fehlerbehandlung nach Nummer.
Anmeldung
SignIn | Erster Faktor | Woher |
|---|---|---|
gwPersonalKey (Vorgabe) | persönlicher Schlüssel (wkl_…) in X-Api-Key | Eigenschaft Key; sonst die Windows-Anmeldeinformationsverwaltung (StoreKey, ForgetKey, HasStoredKey) |
gwWindows | Windows-Konto des Prozesses (Negotiate) | – |
gwSqlLogin | SQL-Anmeldung (HTTP Basic) | UserName, Password |
gwServiceKey | Dienstschlüssel | Umgebungsvariable KeyVariable |
Jede Anmeldung – persönlicher Schlüssel, Dienstschlüssel, Kennwort und Windows-Konto – geht nur über
https oder an den eigenen Rechner; eine http-Adresse eines anderen Rechners lehnt die Klasse vor dem
Senden mit gwErrConfiguration ab.
Den Schlüssel legt StoreKey unter demselben Ziel ab, das der ODBC-Treiber für eine
Verbindung zur Verwaltung derselben Adresse verwendet
(Wkl.Data.OData.Odbc:(persönlicher Schlüssel)@<BaseUrl>/admin/v1/odata/): Ein gespeicherter
Schlüssel dient den verknüpften Tabellen und der Klasse. In der Datenbankdatei steht er nie.
Zweiter Faktor
Verlangt der Dienst einen zweiten Faktor (Antwort 401 mit Wkl-Totp), erfragt die Klasse den
Code, tauscht ihn gegen eine Sitzung und wiederholt die Anfrage. Woher der Code kommt, in dieser
Reihenfolge:
- Eigenschaft
TotpCode(einmal verwendet) – für Code, der selbst fragt. - Ereignis
CodeRequired(Message, Code, Cancel)einer Instanz mitWithEvents. InputBox(läuft auch in der Runtime); abschaltbar mitAskWithInputBox = False.
Ein falscher Code wird mit der Meldung des Dienstes neu erfragt, höchstens dreimal. OpenSession
eröffnet die Sitzung ausdrücklich, ForgetSession vergisst sie. Der ODBC-Treiber hält eine
eigene Sitzung; damit ein Code für beide genügt, übergibt die Anwendung SessionToken dem Treiber
mit dem Schlüsselwort SESSION= einer Verbindung, die sie selbst öffnet (so macht es die
Verwaltungsanwendung). Ohne Übergabe fragen Treiber und Klasse je
einmal.
Unterbrochene Verbindung
Bricht die Verbindung ohne Antwort ab, wiederholt die Klasse die Anfrage nach 1 und 3 Sekunden.
Jede Schreibanfrage trägt einen Idempotency-Key; der Dienst beantwortet eine Wiederholung aus
seinem Gedächtnis, statt ein zweites Mal zu schreiben. Dieses Gedächtnis hält den Schlüssel
10 Minuten und nur im Arbeitsspeicher: Startet der Dienst zwischen Abbruch und Wiederholung neu,
kann eine Anfrage doppelt ankommen (Vorgabe des Dienstes laut HTTP: Verwaltung (Referenz),
Abschnitt „Viele Vorgänge auf einmal“ (Dokumentation des Datendienstes)). Eine abgelaufene
Zeitgrenze (TimeoutSeconds, Vorgabe 60) wird nicht wiederholt: Der Dienst kann die Anfrage noch
ausführen, die Klasse weiß es nicht. Lesen Sie in diesem Fall nach, ob die Änderung angekommen ist.
Was die Klasse schützt und was nicht
- Schlüssel, Kennwort und Windows-Anmeldung sendet sie nur über HTTPS oder an den eigenen Rechner; sonst lehnt sie mit
gwErrConfigurationab. Das Serverzertifikat prüft WinHTTP mit dem Zertifikatsspeicher von Windows; ein ungültiges Zertifikat lässt die Anfrage scheitern, die Klasse schaltet die Prüfung nicht ab. KeyundPasswordhält sie nur im Arbeitsspeicher ihrer Instanz; gespeichert wird ein Schlüssel nur mitStoreKeyin der Windows-Anmeldeinformationsverwaltung des Benutzers.- Ein Dienstschlüssel (
gwServiceKey) wird nie im Code oder in der Datenbank abgelegt, sondern zur Laufzeit aus der UmgebungsvariablenKeyVariablegelesen. Wer diese Variable lesen kann (jeder Prozess des Benutzers), hat den Schlüssel.
Referenz
| Mitglied | Beschreibung |
|---|---|
BaseUrl | Adresse des Dienstes, Schema, Rechner und Port, ohne Pfad |
SignIn, Key, KeyVariable, UserName, Password | Anmeldung, siehe oben |
TotpCode, AskWithInputBox, CodeRequired | Zweiter Faktor |
TimeoutSeconds | Zeitgrenze je Anfrage in Sekunden |
LastStatus, LastMessage | HTTP-Status und Meldung der letzten Antwort |
HasSession, SessionExpiresAt, OpenSession, ForgetSession | Sitzung des zweiten Faktors |
SessionToken | Die Sitzung selbst, zur Übergabe an den ODBC-Treiber desselben Prozesses (SESSION=); nur im Speicher halten |
CredentialTarget, StoreKey, ForgetKey, HasStoredKey | Schlüssel in der Windows-Anmeldeinformationsverwaltung. ForgetKey liefert False und HasStoredKey False nur, wenn kein Schlüssel gespeichert ist; scheitert die Anmeldeinformationsverwaltung selbst, lösen beide gwErrConfiguration aus |
IssueKey(Person, [Label], [ExpiresAt], [ReadOnly], [Databases], [FromNetworks], [ExceptNetworks], [TotpExempt], [Delivery], [OnDemand]) | Schlüssel ausstellen; Delivery link (Vorgabe) oder key; OnDemand = ruht bis zur Freischaltung. Mit key steht der Schlüssel im Klartext in der Antwort und damit in Ihrem VBA-Code: Er darf weder angezeigt noch gespeichert noch geloggt werden. Die Verwaltungsanwendung nutzt deshalb nur link |
ActivateKey(KeyId, Hours) / DeactivateKey(KeyId) | Einen Schlüssel auf Abruf für Hours Stunden freischalten bzw. sofort wieder ruhen lassen; siehe HTTP: Anmeldung (Referenz), Abschnitt „Schlüssel auf Abruf“ (Dokumentation des Datendienstes) |
ExplainSignIn(Person, OriginNames, OriginAddresses, [Scope], [OriginCountries], [OriginOperators], [OriginClients], [OriginTimes]) | Was die Anmelderichtlinie für die Person je Anmeldeart und Herkunft sagt, mit den auslösenden Regeln (rules), den Regeln in Probe (tried) und den von einer Ausnahme aufgehobenen (spared); leere Adresse = unbekannte Herkunft. Die Felder je Herkunft für Land (TH), Netzbetreiber (AS3320), Programm und Zeitpunkt (UTC) fragen „was gälte, wenn …“; leer liest der Dienst sie selbst |
SignInProfile(Person, [Days]) | Was für die Person bei der Anmeldung üblich ist, über die letzten Days Tage (1 bis 3 650, Vorgabe 90): total, activeDays und unter dimensions je Land, Netz, Netzbetreiber, Programm, Verfahren und Stunde die Werte mit Anzahl, erstem und letztem Tag. Nur erfolgreiche Anmeldungen; braucht das Recht sign-in-events (sonst 403), unbekannte Person 404 |
SaveSignInRule(Id, Scope, Method, Effect, Label, [FromNetworks], [ExceptNetworks], [Persons], [ExceptPersons], [WindowsGroups], [ExceptWindowsGroups], [Countries], [ExceptCountries], [Operators], [ExceptOperators], [Clients], [ExceptClients], [Hours], [ExceptHours], [Exceptions], [Mode]) | Anmelderegel samt allen Bedingungen und Ausnahmen in einer Änderung anlegen (Id 0) oder als Ganzes ersetzen – eine ausgelassene Liste ist danach leer, und ohne Mode wird die Regel durchgesetzt. Listen je für und gegen: Netze, Personen (Namen), Windows-Gruppen, Länder, Netzbetreiber, Programme, Zeitfenster; eine leere Personenliste heißt „jeder Aufrufer“. Exceptions: Array aus Scripting.Dictionary mit den Listen persons, windowsGroups, countries, from, operators, clients, hours, dem Ende until (Date in UTC) und label. Mode: Enforce oder Report (nur erproben). Antwort id |
EnrollTotp(Person, [Delivery]), ResetTotp(Person) | Zweiten Faktor einrichten bzw. entfernen |
OwnKeys([DataSource]), IssueOwnKey([Label], [ExpiresAt], [ReadOnly], [Databases], [DataSource]), RevokeOwnKey(Id, [DataSource]) | HTTP: Anmeldung (Referenz), Abschnitt „Selbstbedienung“ (Dokumentation des Datendienstes): eigene Schlüssel auflisten, ausstellen (Antwort key, einmal), sperren. Angemeldet mit gwWindows oder gwSqlLogin; bei einer SQL-Anmeldung nennt DataSource die Datenquelle, an der sie geprüft wird |
TestConnection(DataSource), ReloadCatalog([DataSource]) | Datenquelle prüfen (Antwort reachable; scheitert sie, dazu message, number und failure, die Art des Fehlers unabhängig von der Sprache des Servers), Katalog verwerfen |
ServiceAccount() | Das Konto, unter dem sich der Dienst mit Windows-Anmeldung an Datenbanken anmeldet: account (so sieht es ein SQL Server auf demselben Rechner), networkAccount (auf einem anderen Rechner), kind, domain – der Name, für den die Datenbankverwaltung die Anmeldung anlegt |
SetGeoIpSource(Source, UpdateDays, [Account], [LicenseKey], [RemoveLicenseKey]) | Quelle der Geodatenbank wählen: none, dbip-lite oder maxmind (mit Kontonummer und Lizenzschlüssel); UpdateDays 0 bis 90, 0 = nur auf Befehl. Ohne LicenseKey bleibt der gespeicherte; der Dienst gibt ihn nie zurück |
UpdateGeoIp() | Beide Dateien der Geodatenbank jetzt laden und ohne Neustart in Gebrauch nehmen; Antwort files je Datei mit kind, buildDate, changed |
UploadGeoIp(FileName, [Source], [Force]) | Eine Datei der Geodatenbank übergeben (.mmdb, .mmdb.gz, .tar.gz von MaxMind), für einen Server ohne Internetzugang; Source bestimmt die Namensnennung, Force nimmt auch eine ältere Datei |
ExportLoad([Days]) | Das Lastprotokoll der letzten Days Tage (Vorgabe 30) im Format wkl-load-export/1, ohne Personen, Schlüssel, Adressen und Werte; speichern mit JDoc.Save |
UpdateDatabases() | Die Datenbanken, in die das Update-Modul des Dienstes Pakete einspielt: folder, databases (je Datenbank id, product, gatewayAlias, Verbindung ohne Kennwort, Ordner, Sicherung, settings) und problems (ausgelassene Konfigurationen); siehe HTTP: Verwaltung (Referenz), Abschnitt „Datenbank-Updates“ (Dokumentation des Datendienstes). Die Betriebseinstellungen stehen in der Menge UpdateSettings |
UpdateStatus(DatabaseId), UpdateHistory(DatabaseId, [Skip], [Take]) | Stand einer Datenbank: offene Pakete mit status, reason und deadlineUtc, Sitzungen (sessions), Abweichungen (drift); abgeschlossene Pakete mit ihren Schritten, neueste zuerst (Take 1 bis 100, Vorgabe 20) |
ConfirmUpdate(DatabaseId, Package), DismissUpdate(DatabaseId, Package), RetryUpdate(DatabaseId, Package), CancelUpdateNotice(DatabaseId, Package), MoveUpdateDeadline(DatabaseId, Package, DeadlineUtc) | Entscheidungen über ein Paket (Package = Nummer aus Stand oder Verlauf): bestätigen, verwerfen, erneut einspielen, Ankündigung abbrechen, Frist verschieben (DeadlineUtc als 2026-11-03T06:00:00Z). Antwort message und package (outcome done, announced, waiting oder failed). Anderer Stand des Pakets: gwErrConflict; das Modul spielt gerade ein: gwErrService |
UploadUpdate(DatabaseId, FileName) | Eine Paketdatei (<Produkt>-schema-<Version>.zip, höchstens 64 MiB) in den Eingang der Datenbank legen; der Dienst nimmt sie sofort an. Antwort wie bei einer Entscheidung; dasselbe Paket wartet schon: gwErrConflict |
CheckStore(), BackupStore(), ResealStore() | Speicher prüfen, sichern (in den Ordner sicherungen neben dem Speicher; Antwort file, schemaVersion, bytes), neu versiegeln |
ReadSet(SetName, [Filter], [OrderBy], [Top]) | Eine Menge lesen; Zeilen unter $.value |
CallProcedure(DataSource, Name, Name1, Value1, Name2, Value2, …) | Eine gespeicherte Prozedur aufrufen, Argumente paarweise, Namen ohne @; ein weggelassenes Argument nimmt den Vorgabewert der Prozedur. Werte: Text, Zahlen (Currency und Decimal exakt), Boolean, Date (als ISO-8601-Text, den SQL Server in den Parametertyp umwandelt), Null. Antwort: die erste Ergebnismenge unter $.data ($.data[0].<column>) oder affectedRowCount. Löst die Prozedur selbst eine Meldung aus (THROW, RAISERROR mit Text), kommt sie als gwErrRejected mit ihrem Text. Vertrag: HTTP: eigener Vertrag (Referenz), Abschnitt „Prozeduren aufrufen“ (Dokumentation des Datendienstes); braucht eine Regel mit procedures und POST |
Execute(Method, Path, [Body]) | Jede andere Anfrage, Antwort als JDoc |
Fehler
Jeder Fehler wird mit fester Nummer (WklGatewayError) und deutschem Text ausgelöst; der Text endet mit
der Meldung des Dienstes, wo es eine gibt.
| Konstante | Nummer | Bedeutung |
|---|---|---|
gwErrUnreachable | vbObjectError + 2001 | Keine Verbindung, auch nach Wiederholungen |
gwErrTimeout | + 2002 | Keine Antwort innerhalb TimeoutSeconds |
gwErrUnauthenticated | + 2003 | 401: Schlüssel, Konto oder Kennwort abgelehnt, oder kein Schlüssel vorhanden |
gwErrSecondFactor | + 2004 | Zweiter Faktor nötig und nicht angegeben, oder abgelehnt |
gwErrForbidden | + 2005 | 403 |
gwErrNotFound | + 2006 | 404 |
gwErrBadRequest | + 2007 | 400 |
gwErrConflict | + 2008 | 409, 412: inzwischen geändert |
gwErrRejected | + 2009 | 422: vom Dienst abgelehnt; bei einer Meldung, die die Anwendung in der Datenbank selbst auslöst, endet der Text mit ihr |
gwErrTooMany | + 2010 | 429 |
gwErrService | + 2011 | 5xx |
gwErrAnswer | + 2012 | Antwort ist kein lesbares JSON |
gwErrConfiguration | + 2013 | Einstellungen der Klasse widersprechen sich |
Grenzen
- Treiber und Klasse halten getrennte Sitzungen des zweiten Faktors, solange die Anwendung die Sitzung nicht mit
SESSION=übergibt. - Antworten bis zur Zeitgrenze werden ganz gelesen; für große Datenmengen sind die verknüpften Tabellen (ODBC-Treiber) der Weg, nicht diese Klasse.