Authentifizieren Sie sich mit Immersive per Code: Passwort, MFA und API-Schlüssel
- Nicht definierter Typ
Documentation
Dieser Leitfaden erklärt, wie eine Anwendung direkt die RestFrontage-Authentifizierungsschnittstellen aufruft, erhält ein Immersive Token und verwendet es mit WebAPIs und OData. Die Beispiele erfordern keine immersiven DLLs.
Varianten HTTP, C#, JavaScript, TypeScript, Python und PowerShell .NET-Anwendungen, Webschnittstellen, Backends und Exploit-Skripte abdecken. HTTP-Beispiele zeigen den Vertrag; andere Varianten führen dieselben Austauschvorgänge durch.
In diesem Artikel
1. Wähle den richtigen Modus
| Bedarf | Mode | Ergebnis |
|---|---|---|
| Melden Sie sich bei einem Benutzer an, wenn sein Passwort gemäß der Serverrichtlinie ausreichend ist. | POST /api/Security/Users/Authenticate | Ein Objekt, das enthält Token, oder eine Ablehnung, falls ein MFA erforderlich ist. |
| Melden Sie sich mit MFA-Unterstützung an und melden Sie sich bei einer ersten Konfiguration an. | Posten Sie /api/Security/Mfa/VerifyCredentials und dann VerifyTotp, falls gewünscht. | So sei es Token Sofort, ein Schritt ZeremonieToken vor dem Erhalt des Tokens abgeschlossen zu werden. |
| Ruf eine API von einem Dienst oder einer Automatisierung auf. | Überschriften x-app-name und x-api-key. | Der Aufruf wird direkt authentifiziert; die Antwort bleibt die der aufgerufenen API. |
| Lass RestFrontage Login und MFA anzeigen, ohne diese Bildschirme zu erstellen. | Browser/Authorize und Browser/Token, mit PKCE. | Ein Token nach der Reise im Browser; dieser Modus ist Gegenstand des Artikels, der der gehosteten Verbindungsoberfläche gewidmet ist. |
Ein API-Schlüssel repräsentiert die Anwendung mit Die Rechte des damit verbundenen Kontos. Es kann ohne Passwort oder TOTP verwendet werden. Es verleiht Administratorrechten nicht automatisch.
Bei einer von einer Person genutzten App vermeidet die gehostete Reise die Implementierung des Passwortformulars, QR-Codes und MFA-Eingabes. Dieser Leitfaden behandelt direkte Anrufe, wenn Ihre App diese Interaktionen selbst unterstützt.
flowchart TD
A{"Type de connexion ?"}
A -->|Clé API| B["Envoyer x-app-name et x-api-key à chaque appel"]
B --> C["Appeler les WebAPI ou OData"]
A -->|Compte utilisateur| D["VerifyCredentials : vérifier l'identifiant et le mot de passe"]
D --> E{"Réponse du serveur"}
E -->|authenticated| F["Token disponible"]
E -->|totp_required| G["Saisir le code du téléphone"]
E -->|totp_enrollment_required| H["Configurer l'application TOTP avec le QR code"]
H --> G
G --> I["VerifyTotp : vérifier le code"]
I -->|Code accepté| F
I -->|Code incorrect, nouvel essai autorisé| G
F --> J["Envoyer Authorization: Bearer TOKEN à chaque appel"]
J --> C
2. Vorbereitung auf Einsätze
2.1 Adresse, HTTPS und Identität
Verlassen Sie sich zum Beispiel auf den HTTPS-Ursprung von RestFrontage https://localhost:44333 oder https://rest.exemple.fr In Ihrem Netzwerk. Das Zertifikat muss vom Kunden anerkannt werden.
Das Passwort und der API-Schlüssel stammen von Benutzereingaben oder dem geheimen Speicher deiner App. Sie sollten nicht in veröffentlichtem Code, Captures, Protokollen oder URLs enthalten sein.
Der Client speichert das Token im Speicher. Er sendet es nur an den Server, der es ausgegeben hat. Die untenstehenden Funktionen verweigern Pfade zu einem anderen Server und HTTP leitet um.
2.2 Respektieren Sie JSON-Namen
| Spielfeld | Rolle |
|---|---|
| AccountName, Passwort | Zugangsdaten an den Server gesendet. |
| Token | Letztes Token, das in Autorisierung: Inhaber verwendet werden soll. |
| Status | Phase der MFA-Reise. |
| ZeremonieToken | Vorübergehender Verweis auf die aktuelle Verifikation; es handelt sich nicht um ein Zugriffstoken. |
| ProvisioningUri, ManualKey | Vertrauliche TOTP-Konfigurationsinformationen, vorhanden bei der Registrierung. |
| Code, Botschaft in einem Fehler | Technische Kennung des Fehlers und erklärender Text. |
| Code in der VerifyTotp-Abfrage | Ein sechsstelliger TOTP-Code, der als Zeichenkette übertragen wird. |
Antworten dieser APIs verwenden die PascalCase. Lesen Token, nicht Token, und ZeremonieToken, nicht ZeremonieToken. Einige klassische Antworten können Metadaten enthalten, wie zum Beispiel $type : Die Kunden unten ignorieren sie.
Der Hosted Connection Contract ist eine Ausnahme: Browser/Token gibt Rückkehr access_token, token_type und expires_in. Vermischen Sie die beiden Formate nicht.
2.3 Der Origin-Header für MFA
Straßen MFA/VerifyCredentials, MFA/VerifyTotp und MFA/Cancel erfordert einen JSON-Körper und einen Ursprung, der in ist MFA: Ursprünge.
| Kunde | Herkunftswert |
|---|---|
| .http, C#, Python, PowerShell, JavaScript-Datei in Node.js | Senden Sie es ausdrücklich. In einem lokalen Test, https://localhost:44333 Geeignet, wenn dieser Ursprung vom Server erlaubt ist. |
| JavaScript oder TypeScript in einem Browser | Der Browser sendet ihn automatisch: Er ist der Ursprung der Seite, der den Code ausführt. Das Skript kann ihn nicht durch das von RestFrontage ersetzen. |
Für eine Webanwendung, die auf https://application.exemple.fr Wer ruft https://rest.exemple.fr, haben https://application.exemple.fr in Mfa:Origins und in der CORS-Richtlinie von RestFrontage. Die beiden Steuerelemente haben getrennte Rollen. Ein Ursprung hat keinen Pfad oder Endbalken.
Origin ist weder ein API-Schlüssel noch ein Identitätsnachweis. In einem Nicht-Browser-Client kann dieser Header vom Programm ausgefüllt werden; der Server überprüft immer das Passwort und die MFA. Siehe Ursprung im Browser und CORS.
2.4 Häufige Funktionen von Beispielen
Jede Variante bereitet den HTTP-Client vor, der in den folgenden Abschnitten verwendet wird. SendAsync, Senden, send_request und Senden-Immersiv sind in diesem Artikel verwendete Funktionen, keine Funktionen, die von einer Immersive DLL bereitgestellt werden.
Für C# erstellen Sie eine Konsolen-App .NET 8 oder später ; Schnipsel werden in derselben obersten Anweisungsdatei verwendet, wobei implizite Verwendungen aktiviert sind. Für JavaScript verwenden Sie ein Modul in einem HTTPS-Browser oder Node.js 22 oder später. Die folgenden JavaScript-Aufrufe können auch in TypeScript verwendet werden; der TypScript-Tab gibt eine typisierte Variante der Vorbereitung an.
Python benötigt Python 3.10 oder neuer und Anfragen. Die optionale Umwandlung eines API-Schlüssels in ein Token verwendet ebenfalls Kryptographie :
python -m pip install requests cryptography
PowerShell Samples Ziel PowerShell 7, einschließlich RSA-OAEP-SHA256. Sie zielen nicht auf Windows PowerShell 5.1 ab.
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
var server = new Uri("https://localhost:44333");
var origin = server.GetLeftPart(UriPartial.Authority);
using var http = new HttpClient(new HttpClientHandler
{
AllowAutoRedirect = false,
UseCookies = false
}) { Timeout = TimeSpan.FromSeconds(30) };
async Task<JsonElement> SendAsync(
HttpMethod method, string path, object? body = null,
Dictionary<string, string>? headers = null)
{
if (server.Scheme != "https" || !string.IsNullOrEmpty(server.UserInfo)
|| !path.StartsWith('/') || path.StartsWith("//") || path.Contains('\\'))
throw new ArgumentException("Adresse HTTPS et chemin local attendus.");
var uri = new Uri(server, path);
if (uri.GetLeftPart(UriPartial.Authority) != origin)
throw new ArgumentException("Changement de serveur interdit.");
using var request = new HttpRequestMessage(method, uri);
request.Headers.Accept.ParseAdd("application/json");
if (headers != null)
foreach (var pair in headers) request.Headers.Add(pair.Key, pair.Value);
if (body != null)
request.Content = new StringContent(
JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");
using var response = await http.SendAsync(request);
if (!response.IsSuccessStatusCode)
throw new HttpRequestException(
"Appel refusé : HTTP " + (int)response.StatusCode,
null, response.StatusCode);
using var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
return json.RootElement.Clone();
}
string ReadToken(JsonElement response)
{
if (!response.TryGetProperty("Token", out var value)
|| value.ValueKind != JsonValueKind.String
|| string.IsNullOrWhiteSpace(value.GetString()))
throw new InvalidOperationException("Aucun token d'accès dans cette réponse.");
return value.GetString()!;
}
var mfaHeaders = new Dictionary<string, string> { ["Origin"] = origin };
const server = new URL("https://localhost:44333");
const origin = server.origin;
// Hors navigateur seulement ; dans le navigateur, Origin est automatique.
const mfaHeaders = typeof window === "undefined" ? { Origin: origin } : {};
async function send(method, path, body = undefined, headers = {}) {
if (server.protocol !== "https:" || server.username || server.password
|| !path.startsWith("/") || path.startsWith("//") || path.includes("\\"))
throw new Error("Adresse HTTPS et chemin local attendus.");
const url = new URL(path, server);
if (url.origin !== origin) throw new Error("Changement de serveur interdit.");
const response = await fetch(url, {
method, credentials: "omit", redirect: "error", cache: "no-store",
signal: AbortSignal.timeout(30000),
headers: {
Accept: "application/json",
...(body === undefined ? {} : { "Content-Type": "application/json" }),
...headers
},
...(body === undefined ? {} : { body: JSON.stringify(body) })
});
if (!response.ok) throw new Error("Appel refusé : HTTP " + response.status);
return await response.json();
}
function readToken(response) {
if (typeof response.Token !== "string" || !response.Token)
throw new Error("Aucun token d'accès dans cette réponse.");
return response.Token;
}
import requests
from urllib.parse import urljoin, urlsplit
server = "https://localhost:44333"
origin = server
mfa_headers = {"Origin": origin}
def send_request(method, path, body=None, headers=None):
base = urlsplit(server)
if (base.scheme != "https" or base.username or base.password
or not path.startswith("/") or path.startswith("//") or "\\" in path):
raise ValueError("Adresse HTTPS et chemin local attendus.")
url = urljoin(server, path)
if urlsplit(url).netloc != base.netloc:
raise ValueError("Changement de serveur interdit.")
response = requests.request(
method, url, json=body,
headers={"Accept": "application/json", **(headers or {})},
timeout=30, allow_redirects=False
)
if not 200 <= response.status_code < 300:
raise RuntimeError("Appel refusé : HTTP " + str(response.status_code))
return response.json()
def read_token(response):
token = response.get("Token")
if not isinstance(token, str) or not token:
raise RuntimeError("Aucun token d'accès dans cette réponse.")
return token
$server = [Uri]'https://localhost:44333'
$origin = $server.GetLeftPart([UriPartial]::Authority)
$mfaHeaders = @{ Origin = $origin }
function Send-Immersive {
param(
[string]$Method, [string]$Path,
[object]$Body = $null, [hashtable]$Headers = @{}
)
if ($server.Scheme -ne 'https' -or $server.UserInfo -or
-not $Path.StartsWith('/') -or $Path.StartsWith('//') -or $Path.Contains('\')) {
throw 'Adresse HTTPS et chemin local attendus.'
}
$uri = [Uri]::new($server, $Path)
if ($uri.GetLeftPart([UriPartial]::Authority) -ne $origin) {
throw 'Changement de serveur interdit.'
}
$allHeaders = @{ Accept = 'application/json' }
foreach ($key in $Headers.Keys) { $allHeaders[$key] = $Headers[$key] }
$arguments = @{
Uri = $uri; Method = $Method; Headers = $allHeaders
TimeoutSec = 30; MaximumRedirection = 0; ErrorAction = 'Stop'
}
if ($null -ne $Body) {
$arguments.ContentType = 'application/json; charset=utf-8'
$arguments.Body = ConvertTo-Json -InputObject $Body -Depth 8 -Compress
}
Invoke-RestMethod @arguments
}
function Read-ImmersiveToken {
param([object]$Response)
if ([string]::IsNullOrWhiteSpace($Response.Token)) {
throw "Aucun token d'accès dans cette réponse."
}
$Response.Token
}
const server = new URL("https://localhost:44333");
const origin = server.origin;
// Hors navigateur seulement ; dans le navigateur, Origin est automatique.
const mfaHeaders: Record<string, string> = typeof window === "undefined" ? { Origin: origin } : {};
async function send<T = any>(
method: string, path: string, body?: unknown,
headers: Record<string, string> = {}
): Promise<T> {
if (server.protocol !== "https:" || server.username || server.password
|| !path.startsWith("/") || path.startsWith("//") || path.includes("\\"))
throw new Error("Adresse HTTPS et chemin local attendus.");
const url = new URL(path, server);
if (url.origin !== origin) throw new Error("Changement de serveur interdit.");
const response = await fetch(url, {
method, credentials: "omit", redirect: "error", cache: "no-store",
signal: AbortSignal.timeout(30000),
headers: {
Accept: "application/json",
...(body === undefined ? {} : { "Content-Type": "application/json" }),
...headers
},
...(body === undefined ? {} : { body: JSON.stringify(body) })
});
if (!response.ok) throw new Error("Appel refusé : HTTP " + response.status);
return await response.json() as T;
}
function readToken(response: { Token?: unknown }): string {
if (typeof response.Token !== "string" || !response.Token)
throw new Error("Aucun token d'accès dans cette réponse.");
return response.Token;
}
type MfaReply =
| { Status: "authenticated"; Token: string }
| { Status: "totp_required"; CeremonyToken: string;
ProvisioningUri: null; ManualKey: null }
| { Status: "totp_enrollment_required"; CeremonyToken: string;
ProvisioningUri: string; ManualKey: string };
// Pour typer la réponse : await send<MfaReply>("POST", chemin, corps, mfaHeaders)
Diese Dienstprogramme werfen für jede Nicht-2xx-Antwort einen Fehler und zeigen keine sensiblen Körper an. In deiner Schnittstelle verarbeitest du den HTTP-Status und die Botschaft JSON-Fehler zur Anzeige passender Texte. Einige Ablehnungen sind Text oder haben keinen Körper.
Python verwendet den von Anfragen erkannten Zertifikatsspeicher. Wenn dein Unternehmen eine interne Autorität bereitstellt, konfiguriere sein Zertifikat mit REQUESTS_CA_BUNDLE. Deaktivieren Sie die TLS-Überprüfung nicht. Siehe Dokumentationsanfragen.
2.5 Gib Werte an, die auf deine Anwendung zugeschnitten sind
Die Schnipsel für jeden Modus vervollständigen die obige Vorbereitung. Sie sind kein einzelnes Programm, das vollständig verkettet werden soll: Wählen Sie einen Verbindungsmodus und dann den authentifizierten Anruf.
| Wert | C# / JavaScript / TypeScript | Python | PowerShell |
|---|---|---|---|
| Login eingegeben | AccountName | account_name | $accountName |
| Passwort eingegeben | Passwort | Passwort | $password |
| TOTP-Code als Zeichenkette eingegeben | Code | Code | $code |
| Anwendungsname, der mit dem API-Schlüssel bereitgestellt wird | appName | app_name | $appName |
| API-Schlüssel bereitgestellt vom Administrator | apiKey | api_key | $apiKey |
Diese Variablen müssen vor dem Ausführen des Snippets von deiner Schnittstelle oder deinem Geheimspeicher ausgefüllt werden. Die .http-Beispiele enthalten Werte, die überschrieben werden müssen. Halte diese Testdateien aus dem Repository heraus, wenn sie tatsächliche Geheimnisse enthalten.
3. Klassischer Login und Passwort
3.1 Anfrage und Antwort
Die Berufung POST /api/Security/Users/Authenticate erhält ein JSON-Objekt, das enthält AccountName und Passwort. Dies ist keine HTTP-Basic-Authentifizierung: Es ist kein Basic-Header erforderlich.
@server = https://localhost:44333
@username = compte.exemple
@password = REMPLACER_PAR_LE_MOT_DE_PASSE
### Mot de passe seul, si la politique l'autorise
# @name authenticate
POST {{server}}/api/Security/Users/Authenticate
Content-Type: application/json
Accept: application/json
{
"AccountName": "{{username}}",
"Password": "{{password}}"
}
var authentication = await SendAsync(
HttpMethod.Post, "/api/Security/Users/Authenticate",
new { AccountName = accountName, Password = password });
string token = ReadToken(authentication);
const authentication = await send(
"POST", "/api/Security/Users/Authenticate",
{ AccountName: accountName, Password: password }
);
const token = readToken(authentication);
authentication = send_request(
"POST", "/api/Security/Users/Authenticate",
{"AccountName": account_name, "Password": password}
)
token = read_token(authentication)
$body = @{ AccountName = $accountName; Password = $password }
$authentication = Send-Immersive -Method POST -Path '/api/Security/Users/Authenticate' -Body $body
$token = Read-ImmersiveToken $authentication
Die erfolgreiche Antwort enthält Token und Benutzerinformationen in AuthenticatedUser. Hier sind nur die Felder, die für dieses Beispiel nützlich sind:
{
"Token": "JWT_IMMERSIVE",
"AuthenticatedUser": {
"AccountName": "compte.exemple"
}
}
Ich brauche kein Feld Status Zu dieser klassischen Antwort. Gehen Sie außerdem nicht davon aus, dass alle Eigenschaften des Benutzers in allen Umgebungen vorhanden sind.
In einer .http-Datei müssen spezielle Zeichen im Passwort entweicht werden, um ein gültiges JSON zu bilden. In einem Programm lässt der JSON-Serializer den Wert kodieren; den Körper wird nicht durch Verkettung konstruiert.
3.2 Wann MFA verpflichtend ist
Mit korrekten Identifikatoren gibt diese Route zurück HTTP 403 Wenn MFA für das Konto erforderlich ist:
{
"Code": "mfa_required",
"Message": "Utilisez un client compatible avec la MFA."
}
Das bedeutet nicht, dass OData nicht verfügbar ist: Sie müssen eine MFA-fähige Verbindung abschließen, bevor Sie es aufrufen.
Das Passwort allein bleibt nutzbar, wenn MFA deaktiviert ist oder wenn das Konto im Modus mit Ausnahmen effektiv ausgenommen ist. Das Vorhandensein einer bereits konfigurierten TOTP-Anwendung macht MFA an sich nicht verpflichtend: Es entscheidet die Richtlinie des Servers.
Ein leeres Passwort folgt der bestehenden Servereinstellung. Der Client sollte diese Einstellung nicht ändern oder einen leeren Wert als alternative Verbindung betrachten.
4. Anmeldung mit MFA TOTP
4.1 Wähle den Zweck
Für einen neuen Kunden, senden Sie Anmelden mit-TOTP-Oder Anmelden. Dieser Kurs ist geeignet sowohl für einen bereits registrierten Nutzer als auch für einen neuen Nutzer.
| Zweck | Verwendung |
|---|---|
| Anmelden mit-TOTP-Oder Anmelden | Vollständiger Login: sofortiger Token falls erlaubt, TOTP bei Bedarf, Erstregistrierung oder Neuregistrierung erlaubt, falls erforderlich. |
| login-with-totp | Melden Sie sich ohne Anmeldebildschirm an. Wenn MFA erforderlich ist, muss die Verifizierung bereits eingerichtet sein. |
Diese Werte geben die Kapazität der Customer Journey an; sie erlauben es nicht, das vom Administrator gewählte MFA zu deaktivieren. login-with-totp kann daher ein Token sofort zurückgeben, wenn die Richtlinie für dieses Konto keine MFA verlangt.
4.2 Überprüfen Sie die Qualifikationen
@server = https://localhost:44333
@origin = https://localhost:44333
@username = compte.exemple
@password = REMPLACER_PAR_LE_MOT_DE_PASSE
### Étape 1 : lire Status avant de poursuivre
# @name verifyCredentials
POST {{server}}/api/Security/Mfa/VerifyCredentials
Content-Type: application/json
Accept: application/json
Origin: {{origin}}
{
"Credentials": {
"AccountName": "{{username}}",
"Password": "{{password}}"
},
"Purpose": "login-with-totp-or-enroll"
}
var step = await SendAsync(
HttpMethod.Post, "/api/Security/Mfa/VerifyCredentials",
new {
Credentials = new { AccountName = accountName, Password = password },
Purpose = "login-with-totp-or-enroll"
}, mfaHeaders);
string status = step.GetProperty("Status").GetString()!;
const step = await send(
"POST", "/api/Security/Mfa/VerifyCredentials",
{
Credentials: { AccountName: accountName, Password: password },
Purpose: "login-with-totp-or-enroll"
}, mfaHeaders
);
const status = step.Status;
step = send_request(
"POST", "/api/Security/Mfa/VerifyCredentials",
{
"Credentials": {"AccountName": account_name, "Password": password},
"Purpose": "login-with-totp-or-enroll"
}, mfa_headers
)
status = step["Status"]
$body = @{
Credentials = @{ AccountName = $accountName; Password = $password }
Purpose = 'login-with-totp-or-enroll'
}
$step = Send-Immersive -Method POST -Path '/api/Security/Mfa/VerifyCredentials' -Body $body -Headers $mfaHeaders
$status = $step.Status
4.3 Umgang mit den drei möglichen Reaktionen
Fall 1 — Verbindung abgeschlossen. Wenn der Server die Verbindung ohne zusätzlichen Schritt erlaubt:
{
"Status": "authenticated",
"Token": "JWT_IMMERSIVE"
}
Direkt verwenden Token : ReadToken(step) in C#, readToken(step) in JavaScript/TypeScript, read_token(Schritt) in Python, Read-ImmersiveToken $step in PowerShell. Ruf nicht VerifyTotp an : Es wurde kein CeremonyToken ausgegeben.
Fall 2 — TOTP angefordert. Das Konto hat bereits eine Verifikation:
{
"Status": "totp_required",
"CeremonyToken": "REFERENCE_TEMPORAIRE",
"ProvisioningUri": null,
"ManualKey": null
}
Keep ZeremonieToken im Speicher und zeigt die Eingabe des Telefoncodes an. Es wurden bisher keine Zugangstoken ausgegeben.
Fall 3 — Registrierung beantragt. Das Konto muss seine Verifizierung einrichten:
{
"Status": "totp_enrollment_required",
"CeremonyToken": "REFERENCE_TEMPORAIRE",
"ProvisioningUri": "otpauth://totp/Immersive:compte.exemple?secret=SECRET_FICTIF&issuer=Immersive&algorithm=SHA1&digits=6&period=30",
"ManualKey": "SECRET_FICTIF"
}
Die oben beschriebene URI und das Geheimnis sind anschaulich. In deiner Benutzeroberfläche:
- Generieren Vor Ort der QR-Code repräsentiert genau ProvisioningUri.
- Vorschlag ManualKey als manuelle Eingabelösung, falls das Scannen nicht möglich ist.
- Der Nutzer fügt das Konto in Microsoft Authenticator oder einer anderen TOTP-fähigen App hinzu.
- Er gibt den ersten sechsstelligen Code ein.
- Senden Sie diesen Code mit dem same CeremoniToken an VerifyTotp.
Geben Sie ProvisioningUri nicht an einen Drittanbieter-Webdienst zur QR-Code-Generierung weiter. Diese URI enthält das Geheimnis zur Berechnung zukünftiger Codes. Löschen Sie sie zusammen mit ManualKey und der temporären Referenz nach Erfolg oder Abbruch.
A TOTP ist ein einmaliges Passwort, das aus einem Geheimnis und der Zeit berechnet wird. Immersive Anwendungen hier Sechsstellige Beträge, SHA-1 und eine Periode von 30 Sekunden. Das Telefon kann den Code auch ohne Internet berechnen; man muss immer RestFrontage erreichen können, um das zu überprüfen. Die Vermittlung ist die RFC 6238.
sequenceDiagram
participant U as Utilisateur
participant A as Application cliente
participant R as RestFrontage
participant T as Application TOTP
U->>A: Identifiant et mot de passe
A->>R: VerifyCredentials
alt Connexion immédiatement autorisée
R-->>A: authenticated et Token
else Vérification supplémentaire
R-->>A: CeremonyToken et étape attendue
opt Inscription ou réenregistrement autorisé
A-->>U: QR code et clé manuelle
U->>T: Ajouter le compte
end
T-->>U: Code à six chiffres
U->>A: Saisir le code
A->>R: VerifyTotp avec CeremonyToken et Code
alt Code accepté
R-->>A: authenticated et Token
else Code refusé
R-->>A: HTTP 400 et Message
A-->>U: Corriger la saisie ou attendre le prochain code
end
end
4.4 Bestätigen Sie den Code und holen Sie das Token zurück
Dieser Schritt läuft Erst nach totp_required oder totp_enrollment_required. Die Variable Code ist zum Beispiel eine Zeichenkette, die aus Benutzereingaben abgeleitet ist "012345". Wandeln Sie es nicht in eine Zahl um: Die anfängliche Null ist Teil des Codes.
@totp = 012345
### Étape 2 : seulement si l'étape 1 fournit CeremonyToken
# @name authenticateMfa
POST {{server}}/api/Security/Mfa/VerifyTotp
Content-Type: application/json
Accept: application/json
Origin: {{origin}}
{
"CeremonyToken": "{{verifyCredentials.response.body.$.CeremonyToken}}",
"Code": "{{totp}}"
}
if (status is not ("totp_required" or "totp_enrollment_required"))
throw new InvalidOperationException("Aucune vérification TOTP en attente.");
if (code.Length != 6 || code.Any(c => c is < '0' or > '9'))
throw new ArgumentException("Saisissez six chiffres.");
var authentication = await SendAsync(
HttpMethod.Post, "/api/Security/Mfa/VerifyTotp",
new { CeremonyToken = step.GetProperty("CeremonyToken").GetString(), Code = code },
mfaHeaders);
string token = ReadToken(authentication);
if (!["totp_required", "totp_enrollment_required"].includes(status))
throw new Error("Aucune vérification TOTP en attente.");
if (!/^[0-9]{6}$/.test(code)) throw new Error("Saisissez six chiffres.");
const authentication = await send(
"POST", "/api/Security/Mfa/VerifyTotp",
{ CeremonyToken: step.CeremonyToken, Code: code }, mfaHeaders
);
const token = readToken(authentication);
if status not in ("totp_required", "totp_enrollment_required"):
raise ValueError("Aucune vérification TOTP en attente.")
if len(code) != 6 or any(c not in "0123456789" for c in code):
raise ValueError("Saisissez six chiffres.")
authentication = send_request(
"POST", "/api/Security/Mfa/VerifyTotp",
{"CeremonyToken": step["CeremonyToken"], "Code": code}, mfa_headers
)
token = read_token(authentication)
if ($status -notin @('totp_required', 'totp_enrollment_required')) {
throw 'Aucune vérification TOTP en attente.'
}
if ($code -cnotmatch '^[0-9]{6}$') { throw 'Saisissez six chiffres.' }
$body = @{ CeremonyToken = $step.CeremonyToken; Code = $code }
$authentication = Send-Immersive -Method POST -Path '/api/Security/Mfa/VerifyTotp' -Body $body -Headers $mfaHeaders
$token = Read-ImmersiveToken $authentication
Für beide Purpose-Verbindungen lautet die erfolgreiche Antwort:
{
"Status": "authenticated",
"Token": "JWT_IMMERSIVE"
}
Dies gilt auch nach der Bestätigung einer Registrierung, die mit eingeleitet wurde, Anmelden mit-TOTP-Oder Anmelden : Erfolgreiche Registrierung schließt den Login ab und gibt das Token bereit. Es ist nicht nötig, sofort mit dem Passwort von vorne zu beginnen.
Ein HTTP-200-Status reicht nicht aus, um zu schließen, dass der Benutzer angemeldet ist.
VerifyCredentials können HTTP 200 mit einem ausstehenden MFA-Schritt antworten. Die Verbindung wird nur abgeschlossen, wenn Status ist authentifiziert und ein Token ist vorhanden.
4.5 Ablauf, erneuter Versuch und Abbruch
Eine Überprüfung ist gültig Fünf Minuten. Seine Referenz kann nur einmal erfolgreich verwendet werden. Ein bereits akzeptierter Code kann für eine weitere Verifikation nicht wiederverwendet werden.
Nach einem abgelehnten Code zeigen Sie den Fehler an und erlauben Sie einen neuen Eintrag mit demselben CeremonyToken, solange die Verifizierung gültig bleibt. Versuchen Sie nicht automatisch erneut. Nach Fünf falsche Codes, die Kontoverifizierung wird gesperrt für Fünfzehn Minuten ; Ein Neuanfang mit dem Passwort setzt den Timer nicht zurück.
Wenn die Referenz abgelaufen ist, die Richtlinie geändert wurde oder der Nutzer die Meldung storniert hat, starten Sie erneut bei VerifyCredentials. Nachdem der Administrator ein Telefon zurückgesetzt hat, Anmelden mit-TOTP-Oder Anmelden präsentiert die neue Registrierung, solange die Erneuerungsgenehmigung gültig ist. Es sind keine zusätzlichen Wiederherstellungscodes erforderlich.
Um eine ausstehende Prüfung explizit abzubrechen:
POST {{server}}/api/Security/Mfa/Cancel
Content-Type: application/json
Origin: {{origin}}
{
"CeremonyToken": "{{verifyCredentials.response.body.$.CeremonyToken}}"
}
Die Antwort lautet { "Status": "abgesagt" }. Lösche dann die temporären Daten von deiner Schnittstelle. Abbrechen ist keine Verbindungsabbruch und widerruft kein bereits ausgegebenes finales Token.
4.6 Andere Zwecke sind keine Verbindungsmodi
| Wert | Zweck | Mögliches Ergebnis nach Verifizierung |
|---|---|---|
| Anmeldung | Konfigurieren Sie die Kontoverifizierung in einem autorisierten Verwaltungspfad. | Status: registriert ; Kein Login-Token. |
| Verwaltung | Bestätigen Sie eine geschützte Management-Operation. | Status: Autorisiert und ProofToken ; dieser Beweis ist kein Träger. |
| Verwaltung | Sehen Sie sich die Kontoverifizierungsmethode an. | Status: Qualifikationen und Qualifikationen ; Kein Login-Token. |
| Löschen | Entfernen Sie die Verifizierungsmöglichkeiten, sobald dies durch die Richtlinie erlaubt ist. | Status: gelöscht ; Abgelehnt, falls ein MFA weiterhin erforderlich ist. |
| Nur Referenzen | Der Name, der für die klassische Passwortreise verwendet wird. | Verwendung Benutzer/Authentifizieren Für diese Reise; mach es nicht zum Zweck deines MFA-Kunden. |
Um ein Token mit MFA zu erhalten, verwendet deine Integration die oben beschriebenen beiden Verbindungszwecke. Sie benötigt nicht das Name, was nicht mehr Teil der Abfrage ist.
5. API-Schlüssel-Authentifizierung
5.1 Aufruf-APIs direkt
Hol dir einen gültigen Schlüssel und es Anwendungsname. Der Schlüssel muss innerhalb seiner Gültigkeitsdauer liegen, und das zugehörige Konto muss zur Anmeldung autorisiert sein. Der Anwendungsname wird auf einer Groß- und Kleinschreibungs-unsensitiven Basis verglichen; der Wert des Schlüssels ist far- und kleinschreibungssensitiv.
Ein API-Schlüssel für eine Anwendung sollte in einem Backend, Service oder einer kontrollierten Umgebung verbleiben. Fügen Sie ihn nicht in JavaScript-Dateien ein, die von Seitenbesuchern heruntergeladen werden. Die JavaScript-Beispiele in diesem Abschnitt laufen serverseitig, in Node.js.
@server = https://localhost:44333
@appName = Supervision atelier
@apiKey = REMPLACER_PAR_LA_CLE_API
### Authentification directe par clé API
GET {{server}}/api/Security/Mfa/Context
Accept: application/json
x-app-name: {{appName}}
x-api-key: {{apiKey}}
var keyHeaders = new Dictionary<string, string>
{
["x-app-name"] = appName,
["x-api-key"] = apiKey
};
var account = await SendAsync(
HttpMethod.Get, "/api/Security/Mfa/Context", headers: keyHeaders);
string? name = account.GetProperty("AccountName").GetString();
// Node.js uniquement : la clé reste côté serveur.
const keyHeaders = { "x-app-name": appName, "x-api-key": apiKey };
const account = await send(
"GET", "/api/Security/Mfa/Context", undefined, keyHeaders
);
const name = account.AccountName;
key_headers = {"x-app-name": app_name, "x-api-key": api_key}
account = send_request(
"GET", "/api/Security/Mfa/Context", headers=key_headers
)
name = account["AccountName"]
$keyHeaders = @{ 'x-app-name' = $appName; 'x-api-key' = $apiKey }
$account = Send-Immersive -Method GET -Path '/api/Security/Mfa/Context' -Headers $keyHeaders
$name = $account.AccountName
Die Antwort in diesem Beispiel enthält AccountName, kein Token. Der Schlüssel hat die Anfrage direkt authentifiziert. Du kannst dieselben zwei Header an deine WebAPI oder OData-Route senden.
Der Weg MFA/Kontext Dies wird hier nur verwendet, um das verbundene Konto zu verifizieren. Dieses GET fragt nicht nach einem MFA-Code.
Schick nicht gleichzeitig einen alten Autorisierung: Träger oder ein Authentifizierungscookie: Verwenden Sie eindeutig entweder die API-Schlüssel-Header oder den resultierenden Bearer. Ein API-Schlüssel wird nicht durch Schreiben übertragen Erlaubnis: Träger CLE_API.
6. Verwendung des Tokens mit WebAPIs und OData
6.1 Authentifizierter Anruf
Ob vom Passwort, MFA oder API-Schlüssel – das endgültige Token wird gesendet an Autorisierung: Träger.
### Après Users/Authenticate
GET {{server}}/api/Security/Mfa/Context
Accept: application/json
Authorization: Bearer {{authenticate.response.body.$.Token}}
### Après VerifyTotp
GET {{server}}/api/Security/Mfa/Context
Accept: application/json
Authorization: Bearer {{authenticateMfa.response.body.$.Token}}
### Si VerifyCredentials a répondu authenticated directement
GET {{server}}/api/Security/Mfa/Context
Accept: application/json
Authorization: Bearer {{verifyCredentials.response.body.$.Token}}
### Après Token/Renew avec une clé API
GET {{server}}/api/Security/Mfa/Context
Accept: application/json
Authorization: Bearer {{authenticateApiKey.response.body.$.Token}}
var bearerHeaders = new Dictionary<string, string>
{
["Authorization"] = "Bearer " + token
};
var result = await SendAsync(
HttpMethod.Get, "/api/Security/Mfa/Context", headers: bearerHeaders);
string? accountNameFromToken = result.GetProperty("AccountName").GetString();
const result = await send(
"GET", "/api/Security/Mfa/Context", undefined,
{ Authorization: "Bearer " + token }
);
const accountNameFromToken = result.AccountName;
result = send_request(
"GET", "/api/Security/Mfa/Context",
headers={"Authorization": "Bearer " + token}
)
account_name_from_token = result["AccountName"]
$bearerHeaders = @{ Authorization = 'Bearer ' + $token }
$result = Send-Immersive -Method GET -Path '/api/Security/Mfa/Context' -Headers $bearerHeaders
$accountNameFromToken = $result.AccountName
Für OData behalte denselben Header und ersetze den Pfad durch eine von deinem Server veröffentlichte Sammlung. SammlungsName ist ein Standort, der ersetzt werden soll, nicht eine Straße, wie sie in diesem Artikel genannt wird:
GET {{server}}/odata/NomDeCollection?$top=10
Accept: application/json
Authorization: Bearer {{authenticateMfa.response.body.$.Token}}
Ein gültiges Token beweist die Authentifizierung. Kontorechte, Organisationsfilter und Geschäftsberechtigungen bleiben anwendbar. MFA macht aus einem gewöhnlichen Nutzer keinen Administrator.
6.2 Validieren, ablaufen und erneuern
GET /api/Security/Token/Validate, mit dem Träger, ermöglicht es dir, die Sitzung zu überprüfen. Erfolg ist HTTP 202 akzeptiert, mit einem Objekt, das enthält Thema und IsAdministrator. Testet nicht nur HTTP 200.
GET {{server}}/api/Security/Token/Validate
Accept: application/json
Authorization: Bearer {{authenticateMfa.response.body.$.Token}}
Das Ablaufdatum eines JWT ist im Feld angegeben Erfahrungspunkte. Das Lesen auf der Clientseite wird verwendet, um eine Wiederverbindung zu arrangieren; es ersetzt niemals die Validierung des Tokens durch den Server.
Die klassischen und MFA-Routen in diesem Leitfaden geben kein Aktualisierungstoken zurück. Wenn eine Sitzung nicht mehr akzeptiert wird, wird die Reise für den Authentifizierungsmodus neu gestartet.
Die historische Route Token/Verlängerung kann eine Sitzung erneuern, die noch gültig ist, mit demselben verschlüsselten Körper wie zuvor, aber durch Senden des Gemeinsamer Träger anstatt API-Schlüssel-Headern. Es erlaubt nicht, eine abgelaufene Sitzung wiederherzustellen oder eine MFA-Anforderung zu umgehen. Die neue Antwort muss das Token ersetzen, das der Client hält.
Eine Änderung der MFA-Richtlinie oder ein Reset kann eine Sitzung vor Ablauf unbrauchbar machen. Behandle also immer Server-Ablehnungen, auch wenn die Exp noch ein zukünftiges Datum anzeigt.
7. Verwende einen API-Schlüssel mit WebAPIs und OData
Ein API-Schlüssel authentifiziert jede Anfrage direkt bei RestFrontage. Ihre Anwendung übergibt immer die folgenden zwei Header:
- x-app-name : Der Name der mit dem Schlüssel verbundenen Anwendung.
- x-api-key : Der Wert des Schlüssels.
Eine vorherige Anmeldung oder Token-Abrufung ist nicht erforderlich. Man ruft nicht die Passwort-Login- oder TOTP-Verifizierungsrouten an.
7.1 Rufen Sie an
Die untenstehenden Beispiele führen zwei Abfragen aus:
- Ein WebAPI-Aufruf zu /api/Sicherheit/MFA/Kontext, um den Namen des mit dem Schlüssel verbundenen Kontos zu überprüfen. Trotz ihres Namens benötigt diese Route keinen MFA-Code.
- Ein OData-Anruf zu /odata/EquipmentInstances?$top=10, um bis zu zehn verfügbare Geräte für dieses Konto anzufordern.
Programmierte Varianten verwenden die am Anfang dieses Artikel vorgestellten gängigen Funktionen wieder. Füllen Sie den Namen der Anwendung und ihren Schlüssel mit den von Ihrem Administrator angegebenen Werten ein.
@server = https://localhost:44333
@appName = MonApplication
@apiKey = REMPLACER_PAR_LA_CLE_API
### WebAPI : vérifier le compte connecté
GET {{server}}/api/Security/Mfa/Context
Accept: application/json
x-app-name: {{appName}}
x-api-key: {{apiKey}}
### OData : lire jusqu'à dix équipements
GET {{server}}/odata/EquipmentInstances?$top=10
Accept: application/json
x-app-name: {{appName}}
x-api-key: {{apiKey}}
var keyHeaders = new Dictionary<string, string>
{
["x-app-name"] = appName,
["x-api-key"] = apiKey
};
// WebAPI
var account = await SendAsync(
HttpMethod.Get,
"/api/Security/Mfa/Context",
headers: keyHeaders);
// OData
var equipments = await SendAsync(
HttpMethod.Get,
"/odata/EquipmentInstances?$top=10",
headers: keyHeaders);
// Node.js uniquement : conserver la clé côté serveur.
// Cet extrait s'utilise également en TypeScript.
const keyHeaders = {
"x-app-name": appName,
"x-api-key": apiKey
};
// WebAPI
const account = await send(
"GET",
"/api/Security/Mfa/Context",
undefined,
keyHeaders
);
// OData
const equipments = await send(
"GET",
"/odata/EquipmentInstances?$top=10",
undefined,
keyHeaders
);
key_headers = {
"x-app-name": app_name,
"x-api-key": api_key
}
# WebAPI
account = send_request(
"GET",
"/api/Security/Mfa/Context",
headers=key_headers
)
# OData
equipments = send_request(
"GET",
"/odata/EquipmentInstances?$top=10",
headers=key_headers
)
$keyHeaders = @{
'x-app-name' = $appName
'x-api-key' = $apiKey
}
# WebAPI
$account = Send-Immersive -Method GET -Path '/api/Security/Mfa/Context' -Headers $keyHeaders
# OData
$equipments = Send-Immersive -Method GET -Path '/odata/EquipmentInstances?$top=10' -Headers $keyHeaders
Jede Antwort enthält das Ergebnis der angeforderten Operation: Kontoinformationen für den ersten Anruf, OData-Daten für den zweiten. Aus diesen Antworten lässt sich kein Token extrahieren.
Um eine andere Route aufzurufen, behalten Sie beide Header und passen den Pfad, die HTTP-Methode und den Körper entsprechend der Operation an. OData-Parameter, wie zum Beispiel $filter, $select oder $orderby, bleibt nutzbar, wenn die Sammlung sie unterstützt.
7.2 Behalte Kopfzeilen bei jeder Anfrage
Die API-Schlüssel-Authentifizierung erfolgt bei jedem Aufruf. Eine erfolgreiche erste Anfrage befreit Sie nicht davon, die Header bei nachfolgenden Aufrufen weiterzugeben.
Dies gilt auch für Paging-Anfragen und Aufrufe zu anderen Sammlungen auf demselben Server. Überprüfen Sie, dass eine Paging-Adresse zu Ihrem RestFrontage-Server gehört, bevor Sie den Schlüssel an ihn weitergeben.
Füge keinen Header hinzu Autorisierung: Träger auf diese Aufrufe und senden Sie kein Cookie, das einer anderen Benutzersitzung entspricht.
7.3 Die Rechte bleiben bei dem zugehörigen Konto
Der API-Schlüssel ermöglicht Zugriff auf die Operationen, die für das zugehörige Konto erlaubt sind. Organisationseinschränkungen und Geschäftsberechtigungen bleiben weiterhin anwendbar.
Ein gültiger Schlüssel garantiert keinen Zugriff auf alle Daten oder Operationen. Zum Beispiel hat ein Konto, das berechtigt ist, Geräte einzusehen, nicht automatisch das Recht, diese zu ändern.
Der Schlüssel muss ebenfalls gültig bleiben, und das zugehörige Konto darf sich anmelden. Ein abgelaufener, deaktivierter oder gelöschter Schlüssel kann Anrufe nicht mehr authentifizieren.
Bewahren Sie den Schlüssel in einem geheimen Speicher auf, der für Ihre Anwendung geeignet ist. Speichern Sie ihn nicht in einer URL, einem Log oder in JavaScript-Dateien, die an Nutzer einer Website verteilt werden.
Für eine Webanwendung müssen Aufrufe mit diesem Schlüssel vom Backend durchgeführt werden.
8. Lesefehler ohne den Benutzer zu blockieren
| Antwort | Interpretation und Handlung |
|---|---|
| 400 auf Benutzern/Authentifizieren | Ungültige Anfrage; Überprüfe den Text und alle leeren Passworteinstellungen. |
| 401 auf Benutzern/Authentifizieren | Abgelehnte Zugangsdaten oder Konto nicht verfügbar. Fehlermeldung angezeigt, ohne automatisch erneut zu versuchen. |
| 403, Code: mfa_required Zum klassischen Login | Nutze die MFA-Reise oder den gehosteten Login. |
| 403 auf einer MFA-Route, manchmal ohne JSON-Körper | Überprüfe Origin und Mfa:Origins. Im Browser solltest du auch CORS prüfen. |
| 415 auf einer MFA-Strecke | Inhaltstyp senden: application/json. |
| 400, Code: mfa_verification_failed | Lesenachricht: Falscher Code, bereits verwendet, abgelaufene Referenz, Sperre oder Konfiguration nicht verfügbar. |
| 400, Code: mfa_enrollment_unavailable | Die Neuregistrierungsautorisierung ist nicht mehr nutzbar; bitte den Administrator, die Aktion zu erneuern. |
| 401 mit einem API-Schlüssel | Ungültiger Schlüssel, außer Gültigkeit oder widerrufener abgeleiteter Token; prüfen Sie außerdem x-app-name. |
| 403 mit einem gültigen API-Schlüssel | Das verknüpfte Konto kann abwesend, deaktiviert, abgelaufen oder gesperrt sein. |
| 401 auf einer WebAPI oder OData mit Bearer | Token, das abwesend, abgelaufen, widerrufen oder inkompatibel mit der Richtlinie geworden ist; verbinden Sie den Client erneut. |
| 403 über eine Geschäftstätigkeit | Die Identität wird erkannt, aber die Operation ist nicht autorisiert; überprüfen Sie die Rechte. |
| 503 | Eine Sicherheitsüberprüfung ist vorübergehend nicht verfügbar; zeigen Sie die Nichtverfügbarkeit auf und planen Sie einen neuen vertagten Prozess. |
Nicht alle Ablehnungen haben dasselbe Format. Dein Client sollte den HTTP-Status prüfen, bevor er versucht, ein JSON zu lesen.
Wenn während der MFA-Bestätigung ein Netzwerkausfall auftritt, gehen Sie nicht davon aus, dass die Anfrage nicht ausgeführt wurde: Der Server könnte die Referral verbraucht haben, ohne dass die Antwort den Client erreicht hat. Versuchen Sie die Verbindung bei Bedarf erneut und warten Sie auf den nächsten Code vom Telefon.
9. Historische Touren und Gastgeberverbindung
9.1 Sicherheit/Authentifizierung und SSO
POST /api/Security/Authenticate ist ein alter Eingang, der einen verschlüsselter JSON-String, nicht das hier gezeigte Klartextobjekt AccountName/Passwort. Das Ergebnis davon unterliegt weiterhin der MFA-Richtlinie. Für eine neue direkte Passwortintegration verwenden Sie Benutzer/Authentifizieren oder MFA-Routen.
Der SSO-Login ist eine separate Reise, die mit dem Identity-Provider vor Ort des Kunden konfiguriert wird. Das Senden eines Logins und Passworts an Users/Authenticate verwandelt den Anruf nicht in einen SSO. Ein gültiger SSO-Token behält die Rechte des Kontos; die MFA dieser Reise liegt in der Verantwortung des konfigurierten Anbieters.
9.2 Serverbildschirme wiederverwenden
Wenn Sie die im TOTP-Abschnitt beschriebenen Wechselwirkungen nicht weiter ausführen möchten, verwenden Sie den im Artikel dargestellten Pfad Integrieren Sie immersive Authentifizierung und MFA in Ihr Web- und .NET-Anwendungen.
Kunde öffnet Browser/Authorize mit einer deklarierten Rücksendungsadresse, einem Bundesstaat und PKCE. Es erhält einen temporären Code und löst ihn dann über Browser/Token. Es ruft weder VerifyCredentials noch VerifyTotp selbst auf. Das WPF kann diese Verbindung im externen Browser oder im WebView2-Fenster anzeigen.
Laden Sie WPF- und Hosted Login-Webbeispiele herunter
Dieser Download ist für die Reise mit der Serverschnittstelle. Beispiele für Passwort-, MFA- und API-Schlüsselaufrufe finden sich in den Tabs dieses Artikels.
Integration der immersiven Authentifizierung
10. Verifizieren Sie Ihre Integration
Überprüfen Sie die Fälle, die Ihrer Anwendung entsprechen:
- Ein Konto, das nur mit Passwort eingeloggt werden kann.
- Ein Konto, das bereits registriert ist und dem MFA unterliegt.
- Ein Konto, das MFA unterliegt und seine Verifizierung zum ersten Mal einrichtet.
- Eine Neuregistrierung ist nach dem Reset erlaubt.
- Ein falscher TOTP-Code, ein bereits verwendeter Code, eine Stornierung und eine abgelaufene Referenz.
- Ein gültiger API-Schlüssel, ein abgelaufener Schlüssel und ein deaktiviertes zugeordnetes Konto.
- Ein erfolgreicher Call, ein abgelehnter Token und eine Operation, die rechtlich verboten ist.
Der Kunde muss unterscheiden zwischen eine laufende MFA-Phase, Eine Verbindung wurde beendet und Ein autorisierter Geschäftsbetrieb. Dies sind drei verschiedene Ergebnisse.