OAuth 2.0 Überblick
RFC 6749 - Das OAuth 2.0 Authorization Framework spezifiziert ein Protokoll für die Autorisierung von Diensten unter Verwendung einer Drittanbieteranwendung. OAuth 2.0 verwendet Token, um die Autorisierung vom Dienst und den Benutzern zu abstrahieren. Diese Methode ist sicherer, da der Eigentümer des Dienstes sich nicht um die Anmeldedaten der Benutzer kümmern muss. Es ist ein Ersatz für RFC 5849 OAuth 1.0.
Das OAuth 2.0-Framework definiert zwei Client-Typen, öffentlich oder vertraulich, und Abläufe wie den Autorisierungscode-Ablauf, die implizite Code-Gewährung und mehrere andere für die Autorisierung. Eine typische Qt-Anwendung wird als öffentliche native Anwendung betrachtet. Eine öffentliche Client-Anwendung ist eine Anwendung, bei der nicht darauf vertraut werden kann, dass sensible Informationen wie Passwörter in die ausgelieferte Binärdatei eingebettet werden.
RFC 8252 OAuth 2.0 for Native Apps definiert die Best Practices für native Anwendungen weiter. Insbesondere empfiehlt RFC 8252 den Autorisierungsfluss mit dem Browser. Daher bieten die QtNetworkAuth Klassen eine konkrete Implementierung dieses Flusses.
Neu in Qt 6.9, QtNetworkAuth bietet Unterstützung für RFC 8628 - OAuth 2.0 Device Authorization Grant. Dieser Gerätefluss ist für Geräte gedacht, die nur begrenzte oder unpraktische Eingabemöglichkeiten haben. Bei diesem Fluss wird für die Autorisierungserteilung ein sekundäres Gerät wie z. B. Smartphones anstelle des Geräts verwendet. Beispiele für diese Geräte sind Fernsehgeräte, Medienkonsolen, Maschinen-HMIs und IoT-Geräte. Der Benutzer kann dann eine Anwendung auf seinem Smartphone verwenden, um das Gerät zu autorisieren.
In der folgenden Tabelle sind die beiden von Qt Network Authorization unterstützten OAuth 2.0-Flows aufgeführt:
Aspekt | Fluss des Autorisierungscodes | Fluss der Geräteautorisierung |
---|---|---|
Netzwerkverbindung | Ja | Ja |
Benutzer-Interaktion | Browser / User-Agent auf demselben Gerät | Browser / User-Agent auf einem anderen Gerät |
Redirect-Behandlung erforderlich | Ja | Nein |
Eingabefähigkeit auf dem Gerät | Umfangreiche Eingabemöglichkeiten | Eingeschränkte oder keine Eingabemöglichkeiten |
Zielgruppen | Desktop und mobile Anwendungen | TVs, Konsolen, HMIs, IoT-Geräte |
OAuth 2.0 erfordert die Verwendung eines User-Agents, der in der Regel ein Browser ist. Weitere Informationen finden Sie unter Qt OAuth2 Browser Support.
OAuth 2.0-Klassen
Qt Network Authorization bietet sowohl konkrete als auch abstrakte OAuth 2.0-Klassen. Die abstrakten Klassen sind für die Implementierung benutzerdefinierter Abläufe gedacht, während die konkreten Klassen eine konkrete Implementierung bieten.
Eine Liste der C++-Klassen finden Sie auf der Seite QtNetworkAuth.
Qt Network Authorization hat zwei abstrakte Klassen für die Implementierung von OAuth 2.0-Flows:
- Eine OAuth 2.0 Flow-Implementierungsklasse stellt die Haupt-API zur Verfügung und ist der Orchestrator des Flows. Die abstrakte Klasse ist QAbstractOAuth2, und die konkreten Implementierungen sind QOAuth2AuthorizationCodeFlow und QOAuth2DeviceAuthorizationFlow.
- Eine Reply-Handler-Klasse, die Weiterleitungen und Antworten von einem Autorisierungsserver verarbeitet. Die abstrakte Klasse des Reply-Handlers ist QAbstractOAuthReplyHandler, und die konkreten Klassen sind QOAuthHttpServerReplyHandler und QOAuthUriSchemeReplyHandler. Der Hauptunterschied zwischen den Antwort-Handlern besteht in der Art der Weiterleitungen, die sie verarbeiten. QOAuth2AuthorizationCodeFlow verwendet einen Antwort-Handler, um die Weiterleitungen zu verarbeiten, und QOAuth2DeviceAuthorizationFlow, das nicht auf Weiterleitungen basiert, verwendet keine Antwort-Handler.
Ablauf des Autorisierungscodes
Dieser Abschnitt gibt einen Überblick über den Autorisierungscodefluss aus RFC 6749 - Authorization Code und RFC 8252 - Authorization Request from a Native App für native Anwendungen.
Betrachten Sie die folgende Beispielkonfiguration:
QOAuth2AuthorizationCodeFlow m_oauth; QOAuthUriSchemeReplyHandler m_handler; m_oauth.setAuthorizationUrl(QUrl(authorizationUrl)); m_oauth.setTokenUrl(QUrl(accessTokenUrl)); m_oauth.setClientIdentifier(clientIdentifier); m_oauth.setRequestedScopeTokens({scope}); connect(&m_oauth, &QAbstractOAuth::authorizeWithBrowser, this, &QDesktopServices::openUrl); connect(&m_oauth, &QAbstractOAuth::granted, this, [this]() { // Here we use QNetworkRequestFactory to store the access token m_api.setBearerToken(m_oauth.token().toLatin1()); m_handler.close(); }); m_handler.setRedirectUrl(QUrl{"com.example.myqtapp://oauth2redirect"_L1}); m_oauth.setReplyHandler(&m_handler); // Initiate the authorization if (m_handler.listen()) { m_oauth.grant(); }
Phasen des Autorisierungsflusses
Der RFC 6749 Authorization Code Flow hat zwei Hauptstufen: Ressourcenautorisierung (einschließlich der erforderlichen Benutzerauthentifizierung), gefolgt von einer Access Token-Anforderung. Darauf folgen optional die Verwendung des Zugangstokens und die Aktualisierung des Zugangstokens. Die folgende Abbildung veranschaulicht diese Phasen:
- In der Autorisierungsphase wird der Benutzer authentifiziert, und der Benutzer autorisiert den Zugriff auf die Ressourcen. Dies erfordert eine Browser-Interaktion des Benutzers.
- Nach der Autorisierung wird der erhaltene Autorisierungscode verwendet, um ein Zugriffstoken und optional ein Refresh-Token anzufordern.
- Sobald das Zugriffstoken erworben wurde, verwendet die Anwendung es für den Zugriff auf die gewünschten Ressourcen. Das Zugriffstoken ist in den Ressourcenanforderungen enthalten, und es obliegt dem Ressourcenserver, die Gültigkeit des Tokens zu überprüfen. Es gibt mehrere Möglichkeiten, das Token als Teil der Anfragen mit Inhaber-Token einzubinden. Die Aufnahme des Tokens in den HTTP
Authorization
Header ist wohl die gebräuchlichste. - Auffrischung des Tokens. Zugriffstoken laufen in der Regel relativ schnell ab, zum Beispiel nach einer Stunde. Wenn die Anwendung zusätzlich zum Zugriffstoken ein Refresh-Token erhalten hat, kann das Refresh-Token zur Anforderung eines neuen Zugriffstokens verwendet werden. Anwendungen können länger gültige Refresh-Tokens beibehalten, um eine neue Autorisierungsphase (und damit eine weitere Browser-Interaktion) zu vermeiden.
Details und Anpassungen
OAuth 2.0-Abläufe sind dynamisch und die Implementierung der Spezifikationen kann anfangs schwierig sein. Die folgende Abbildung veranschaulicht die wichtigsten Details eines erfolgreichen Autorisierungscodeflusses.
Aus Gründen der Übersichtlichkeit lässt die Abbildung einige Signale weg, zeigt aber insgesamt die Details und die wichtigsten Anpassungspunkte. Bei den Anpassungspunkten handelt es sich um die verschiedenen Signale und Slots, die die Anwendung verwenden kann, sowie um die Rückrufe, die mit QAbstractOAuth::setModifyParametersFunction() und QAbstractOAuth2::setNetworkRequestModifier() eingestellt werden können.
Auswahl eines Antwort-Handlers
Die Entscheidung, welcher Handler verwendet werden soll, hängt vom redirect_uri-Element ab. Unter redirect_uri
wird festgelegt, wohin der Browser nach Abschluss der Autorisierungsphase umgeleitet wird.
Für den Empfang der Autorisierungsantwort in nativen Anwendungen legt RFC 8252 drei Haupttypen von Antwort-URI-Schemata fest: private-use, loopback und https.
- Privat genutzte URIs: Können verwendet werden, wenn das Betriebssystem einer Anwendung erlaubt, ein benutzerdefiniertes URI-Schema zu registrieren. Beim Versuch, eine URL mit einem solchen benutzerdefinierten Schema zu öffnen, wird die entsprechende native Anwendung geöffnet. Siehe QOAuthUriSchemeReplyHandler.
- HTTPS-URIs: Kann verwendet werden, wenn das Betriebssystem der Anwendung erlaubt, eine benutzerdefinierte HTTPS-URL zu registrieren. Beim Versuch, diese URL zu öffnen, wird die zugehörige native Anwendung geöffnet. Dieses Schema wird empfohlen, wenn das Betriebssystem es unterstützt. Siehe QOAuthUriSchemeReplyHandler.
- Loopback-Schnittstellen: Diese werden üblicherweise für Desktop-Anwendungen und Anwendungen während der Entwicklung verwendet. QOAuthHttpServerReplyHandler ist so konzipiert, dass diese URIs von einem lokalen Server verarbeitet werden, der die Umleitung vornimmt.
Die Wahl hängt von verschiedenen Faktoren ab, wie z. B.:
- Vom Anbieter des Autorisierungsservers unterstützte Umleitungs-URIs. Die Unterstützung variiert von Anbieter zu Anbieter und ist oft spezifisch für einen bestimmten Client-Typ und ein bestimmtes Betriebssystem. Außerdem kann die Unterstützung davon abhängen, ob die Anwendung veröffentlicht ist oder nicht.
- URI-Umleitungsschemata, die von der/den Zielplattform(en) unterstützt werden.
- Anwendungsspezifische Benutzerfreundlichkeit, Sicherheit und andere Anforderungen.
RFC 8252 empfiehlt die Verwendung des https
Schemas aufgrund von Sicherheits- und Benutzerfreundlichkeitsvorteilen gegenüber den anderen Methoden.
OAuth 2.0 Geräteautorisierung Grant
RFC 8628 OAuth 2.0 Device Authorization Grant ist für angeschlossene Geräte gedacht, deren Eingabemöglichkeiten begrenzt sind oder bei denen die Verwendung eines User-Agent-Browsers nicht sinnvoll ist. Beispiele für Geräte, die diesen Fluss verwenden, sind intelligente Geräte, die externe Geräte zur Autorisierung benötigen.
Betrachten Sie die folgende Beispielkonfiguration:
m_deviceFlow.setAuthorizationUrl(QUrl(authorizationUrl)); m_deviceFlow.setTokenUrl(QUrl(accessTokenUrl)); m_deviceFlow.setRequestedScopeTokens({scope}); m_deviceFlow.setClientIdentifier(clientIdentifier);// Die Notwendigkeit für ein Client-Geheimnis hängt vom Autorisierungsserver abm_deviceFlow.setClientIdentifierSharedKey(clientSecret); connect(&m_deviceFlow, &QOAuth2DeviceAuthorizationFlow::authorizeWithUserCode, this,[](const QUrl &verificationUrl, const QString &userCode, const QUrl &completeVerificationUrl) { if (completeVerificationUrl.isValid()) { // Wenn der Autorisierungsserver eine vollständige URL // zur Verfügung gestellt hat , die bereits die erforderlichen Daten als Teil der URL-Parameter enthält, // können Sie diese verwenden qDebug() << "Complete verification uri:" << completeVerificationUrl; } else { // Der Autorisierungsserver hat nur die Verifizierungs-URL bereitgestellt; verwenden Sie diese qDebug() << "Verification uri and usercode:" << verificationUrl << userCode; } } ); connect(&m_deviceFlow, &QAbstractOAuth::granted, this, [this](){ // Hier verwenden wir QNetworkRequestFactory zum Speichern des Zugriffstokensm_api.setBearerToken(m_deviceFlow.token().toLatin1()); }); m_deviceFlow.grant();
Stufen der Geräteautorisierung Erteilung
Der Ablauf der Geräteautorisierungserteilung besteht aus drei Hauptphasen: Initialisierung der Autorisierung, Abfrage von Token und Abschluss der Autorisierung. Danach folgen optional die Verwendung der Token und die Aktualisierung der Token. Die folgende Abbildung veranschaulicht diese Phasen:
- Die Autorisierung wird initialisiert, indem eine HTTP-Anfrage an den Autorisierungsserver gesendet wird. Der Autorisierungsserver liefert als Antwort einen Benutzercode, Verifizierungs-URLs und einen Gerätecode.
- Nach der Initialisierung der Autorisierung erhält der Benutzer einen Benutzercode und Verifizierungs-URL(s), um die Autorisierung abzuschließen. Der Mechanismus für den Endbenutzer ist unterschiedlich: Es kann eine sichtbare URL auf dem Bildschirm, ein QR-Code, eine E-Mail usw. sein. Weitere Informationen finden Sie in RFC 8628 - User Interaction.
- Während der Endbenutzer auf den Abschluss der Autorisierung wartet, fragt der Gerätefluss den Autorisierungsserver nach Token ab. Der im vorherigen Schritt erhaltene Gerätecode wird verwendet, um die Autorisierungssitzung abzugleichen. Das Abfrageintervall wird vom Autorisierungsserver festgelegt und beträgt normalerweise 5 Sekunden.
- Sobald der Endbenutzer die Autorisierung akzeptiert oder verweigert hat, antwortet der Autorisierungsserver auf eine Abfrage mit den angeforderten Token oder einem Fehlercode, falls die Autorisierung verweigert wurde, und die Autorisierung ist abgeschlossen.
Details und Anpassungen
Die folgende Abbildung veranschaulicht den Ablauf der Geräteautorisierungserteilung im Detail. Die Abbildung zeigt die wichtigsten Anpassungspunkte, die manchmal erforderlich sind. Zum Beispiel proprietäre Parameter oder zusätzliche Authentifizierungsnachweise.
Token aktualisieren
Aktualisierungs-Tokens erfordern, dass der Autorisierungsserver während der Autorisierung ein Aktualisierungs-Token bereitstellt. Die Bereitstellung eines Refresh-Tokens liegt im Ermessen des Autorisierungsservers: Einige Server stellen es immer bereit, andere nie und wieder andere nur dann, wenn eine bestimmte scope in der Autorisierungsanfrage enthalten war.
Die folgende Abbildung veranschaulicht die Aktualisierung des Tokens im Detail:
Wie in der obigen Abbildung dargestellt, sind die üblichen Anpassungspunkte auch bei der Aktualisierung von Token verfügbar.
Um die Token nach einem Anwendungsstart zu aktualisieren, muss die Anwendung das Aktualisierungs-Token sicher aufbewahren und mit QAbstractOAuth2::setRefreshToken setzen. QAbstractOAuth2::refreshTokens kann dann aufgerufen werden, um neue Token anzufordern.
Neu in Qt 6.9 können Anwendungen die Token automatisch aktualisieren - siehe QAbstractOAuth2::accessTokenAboutToExpire, QAbstractOAuth2::autoRefresh und QAbstractOAuth2::refreshLeadTime.
Die Ablaufzeit für ein Refresh-Token wird im Allgemeinen nicht vom Autorisierungsserver angegeben (abgesehen von der Dokumentation des Servers). Ihre Gültigkeit kann Tage, Monate oder länger betragen. Außerdem können Refresh-Tokens, wie andere Token auch, jederzeit vom Benutzer widerrufen und damit ungültig gemacht werden. Daher ist es wichtig, dass ein fehlgeschlagener Aktualisierungsversuch mit QAbstractOAuth::requestFailed oder QAbstractOAuth2::serverReportedErrorOccurred richtig erkannt wird.
OAuth 2.0-Abläufe erfordern viele Benutzerinteraktionen, die sich störend auf das Benutzererlebnis auswirken können. Um diese Interaktionen zu minimieren, können Token für den Benutzer stillschweigend aufgefrischt werden. Weitere Informationen finden Sie im RFC 6749 - Refreshing Access Tokens.
Qt OpenID Connect Unterstützung
OpenID Connect (OIDC) ist eine einfache Identitätsschicht auf der Grundlage von OAuth 2.0. OIDC kann einen Autorisierungsserver für die Authentifizierung der Identität eines Benutzers verwenden. Der Zugriff auf einfache Benutzerprofilinformationen ist mit OIDC ebenfalls möglich.
Die Unterstützung von Qt für OIDC beschränkt sich im Moment auf das Abrufen von ID-Tokens. Ein ID-Token ist ein JSON-Web-Token (JWT), das Angaben über das Authentifizierungsereignis enthält.
Hinweis: ID-Token-Validierung oder ID-Token-Entschlüsselung ist derzeit nicht implementiert. Sie müssen eine JWT-Bibliothek eines Drittanbieters verwenden, um JWT-Token zu signieren oder zu überprüfen.
Unter der Voraussetzung, dass die Anwendung in der Lage ist, die empfangenen Token zu validieren, kann das Token verwendet werden, um die Identität des Benutzers zuverlässig festzustellen (solange der OIDC-Anbieter selbst vertrauenswürdig ist).
ID-Tokens sind sensible Informationen und sollten geheim gehalten werden; sie sind nicht dasselbe wie Zugangs-Tokens. ID-Tokens sind nicht zum Versenden in API-Aufrufen gedacht - dafür ist das Zugriffstoken gedacht. Beachten Sie, dass einige Anbieter das gleiche JWT-Format für Zugriffstoken verwenden, was jedoch nicht mit den tatsächlichen ID-Tokens zu verwechseln ist, die das gleiche Format verwenden. Bei ID-Tokens ist der Client, der das Token erhält, für die Überprüfung des Tokens verantwortlich, während bei Zugriffstokens der Ressourcenserver, der das Token akzeptiert, für die Überprüfung verantwortlich ist.
Abrufen eines ID-Tokens
Das Abrufen eines ID-Tokens ist ähnlich wie das Abrufen eines Zugriffstokens. Zunächst müssen wir den entsprechenden Bereich festlegen. Der Anbieter des Autorisierungsservers kann zusätzliche Bereichsangaben wie profile
und email
unterstützen, aber alle OIDC-Anfragen müssen den Bereich openid
enthalten:
m_oauth.setRequestedScopeTokens({"openid"});
Für OIDC wird dringend empfohlen, den Parameter nonce zu verwenden. Dazu ist sicherzustellen, dass der entsprechende NonceMode eingestellt ist.
// This is for illustrative purposes, 'Automatic' is the default mode m_oauth.setNonceMode(QAbstractOAuth2::NonceMode::Automatic);
Im letzten Schritt können wir entweder auf das Signal QAbstractOAuth2::granted oder direkt auf das Signal QAbstractOAuth2::idTokenChanged warten:
connect(&m_oauth, &QAbstractOAuth2::idTokenChanged, this, [this](const QString &token) { Q_UNUSED(token); // Handle token });
Validierung eines ID-Tokens
Die Validierung des empfangenen ID-Tokens ist ein kritischer Teil des Authentifizierungsflusses und, wenn vollständig implementiert, eine etwas komplizierte Aufgabe. Lesen Sie die vollständigen Informationen unter OpenID Connect ID Validation.
Als kleine Zusammenfassung besteht die Validierung aus diesen Schritten:
- Entschlüsseln des Tokens, falls erforderlich(siehe JWE)
- Extrahieren des Token-Headers, der Nutzdaten und der Signatur
- Validierung der Signatur
- Validierung der Felder der Nutzdaten (z. B.
aud, iss, exp, nonce, iat
)
Qt bietet derzeit keine Unterstützung für die Validierung von ID-Token, aber es gibt JWT-Bibliotheken von Drittanbietern, wie z. B. jwt-cpp.
Beispiel für ID Token Verifizierung
Dieser Abschnitt veranschaulicht ein einfaches Verifizierungsbeispiel. Als Voraussetzung muss die Entwicklungsumgebung über OpenSSL-Bibliotheken und jwt-cpp im Include-Ordner unter dem Quellverzeichnis des Anwendungsprojekts verfügen.
In der Datei CMakeLists.txt
des Anwendungsprojekts wird zunächst geprüft, ob die Voraussetzungen erfüllt sind:
find_package(OpenSSL 1.0.0 QUIET) set(JWT_CPP_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include") if(OPENSSL_FOUND AND EXISTS "${JWT_CPP_INCLUDE_DIR}/jwt-cpp/jwt.h")
Dann fügen wir die erforderlichen Includes und Bibliotheken hinzu:
target_include_directories(networkauth_oauth_snippets PRIVATE "${JWT_CPP_INCLUDE_DIR}") target_link_libraries(networkauth_oauth_snippets PRIVATE OpenSSL::SSL OpenSSL::Crypto) target_compile_definitions(networkauth_oauth_snippets PRIVATE JWT_CPP_AVAILABLE)
In die Quelldateien der Anwendung wird die Verifikationsbibliothek aufgenommen:
#ifdef JWT_CPP_AVAILABLE #include "jwt-cpp/jwt.h" #endif
Sobald die Anwendung ein ID-Token erhält, ist es an der Zeit, es zu verifizieren. Zuerst wird ein passender Schlüssel aus JSON Web Key Sets (JWKS) gefunden, siehe OpenID Connect Discovery).
try { const auto jwt = jwt::decode(m_oauth.idToken().toStdString()); const auto jwks = jwt::parse_jwks(m_jwks->toJson(QJsonDocument::Compact).toStdString()); const auto jwk = jwks.get_jwk(jwt.get_key_id());
Und dann erfolgt die eigentliche Verifizierung:
// Hier verwenden wir Modulus und Exponent zur Ableitung des Schlüssels const auto n = jwk.get_jwk_claim("n").as_string(); // Modulus const auto e = jwk.get_jwk_claim("e").as_string(); // Exponent if (n.empty() || e.empty()) { qWarning() << "Modulus or exponent empty"; return false; } if (jwt.get_algorithm() != "RS256") { // Dieses Beispiel unterstützt nur RS256 qWarning() << "Unsupported algorithm:" << jwt.get_algorithm(); return false; } if (jwk.get_jwk_claim("kty").as_string() != "RSA") { qWarning() << "Unsupported key type:" << jwk.get_jwk_claim("kty").as_string(); return false; } if (jwk.has_jwk_claim("use") && jwk.get_jwk_claim("use").as_string() != "sig") { qWarning() << "Key not for signature" << jwk.get_jwk_claim("use").as_string(); return false; } // Einfache minimale Verifizierung (lässt Sonderfälle und z.B. 'sub'-Verifizierung aus). // jwt-cpp prüft auch 'exp', 'iat' und 'nbf', wenn sie vorhanden sind. const auto keyPEM = jwt::helper::create_public_key_from_rsa_components(n, e); auto verifier = jwt::verify() .allow_algorithm(jwt::algorithm::rs256(keyPEM)) . with_claim("nonce", jwt::claim(m_oauth.nonce().toStdString())) . with_issuer(m_oidcConfig->value("issuer"_L1).toString().toStdString()) . with_audience(std::string(clientIdentifier.data())) . leeway(60UL); verifier.verify(jwt); qDebug() << "ID Token verified successfully"; return true; } catch(const std::exception &e) { // Fehler behandeln. Alternativ Fehlerparameter an jwt-cpp-Aufrufe übergeben qWarning() << "ID Token verification failed" << e.what(); return false; }
Lesen von ID-Token-Werten
Das ID-Token liegt im JSON-Web-Token-Format (JWT) vor und besteht aus einem Header-, einem Payload- und einem Signaturteil, die durch Punkte getrennt sind .
.
Das Lesen der Werte des ID-Tokens ist einfach. Nehmen wir als Beispiel an, es gäbe eine struct:
struct IDToken { QJsonObject header; QJsonObject payload; QByteArray signature; };
Und eine Funktion:
std::optional<IDToken> parseIDToken(const QString &token) const;
Das Token kann mit extrahiert werden:
if (token.isEmpty()) return std::nullopt; QList<QByteArray> parts = token.toLatin1().split('.'); if (parts.size() != 3) return std::nullopt; QJsonParseError parsing; QJsonDocument header = QJsonDocument::fromJson( QByteArray::fromBase64(parts.at(0), QByteArray::Base64UrlEncoding), &parsing); if (parsing.error != QJsonParseError::NoError || !header.isObject()) return std::nullopt; QJsonDocument payload = QJsonDocument::fromJson( QByteArray::fromBase64(parts.at(1), QByteArray::Base64UrlEncoding), &parsing); if (parsing.error != QJsonParseError::NoError || !payload.isObject()) return std::nullopt; QByteArray signature = QByteArray::fromBase64(parts.at(2), QByteArray::Base64UrlEncoding); return IDToken{header.object(), payload.object(), signature};
In einigen Fällen kann das Token als JSON Web Encryption (JWE ) verschlüsselt sein, das intern ein JWT-Token enthält. In diesem Fall muss das Token zuerst entschlüsselt werden.
OpenID Connect-Ermittlung
OpenID Connect Discovery definiert die Mittel, um benötigte OpenID-Anbieterdetails zu ermitteln, um mit ihnen zu interagieren. Dazu gehören Informationen wie authorization_endpoint
und token_endpoint
URLs.
Während diese Anbieterdetails statisch in der Anwendung konfiguriert werden können, kann das Ermitteln der Details zur Laufzeit mehr Flexibilität und Robustheit bei der Interaktion mit verschiedenen Anbietern bieten.
Der Abruf des Discovery-Dokuments ist eine einfache HTTP-GET-Anfrage. Das Dokument befindet sich normalerweise unter https://<domain name>/.well-known/openid_configuration
.
m_network->get(request, this, [this](QRestReply &reply) { if (reply.isSuccess()) { if (auto doc = reply.readJson(); doc && doc->isObject()) m_oidcConfig = doc->object(); // Store the configuration } });
Insbesondere für die Token-Validierung bietet das jwks_uri-Feld einen Link für den Zugriff auf die aktuellen (öffentlichen) Sicherheitsnachweise. Damit entfällt die Notwendigkeit, solche Anmeldeinformationen direkt in der Anwendung zu kodieren. Dies hilft auch bei der Schlüsselrotation; die Anbieter können die verwendeten Schlüssel von Zeit zu Zeit ändern, so dass es wichtig ist, einen aktuellen Schlüssel zu haben.
Das Abrufen der Schlüssel ist ebenfalls eine einfache HTTP-GET-Anfrage:
m_network->get(request, this, [this](QRestReply &reply) { if (reply.isSuccess()) { if (auto doc = reply.readJson(); doc && doc->isObject()) m_jwks = doc; // Use the keys later to verify tokens } });
Der Schlüsselsatz enthält in der Regel mehrere Schlüssel. Der richtige Schlüssel wird im JWT-Header angegeben (es muss darauf geachtet werden, dass die Schlüssel richtig zugeordnet werden; eine einfache Überprüfung des Feldes key id, kid
, ist nicht ausreichend).
OpenID UserInfo Endpunkt
Eine alternative Möglichkeit, auf Benutzerinformationen zuzugreifen, ist die Verwendung des OpenID Connect UserInfo-Endpunkts, sofern der OIDC-Anbieter dies unterstützt. Die URL für die Benutzerinformationen befindet sich im Feld userinfo_endpoint
des OpenID Connect Discovery-Dokuments.
Der UserInfo-Endpunkt verwendet nicht das ID-Token, sondern der Zugriff erfolgt über das Zugriffstoken. Der Zugriff auf die UserInfo ist ähnlich wie der Zugriff auf jede andere Ressource mit einem Zugriffstoken.
Angenommen, das Zugriffs-Token wird empfangen und z. B. gesetzt von:
QNetworkRequestFactory userInfoApi(url); userInfoApi.setBearerToken(m_oauth.token().toLatin1());
Dann ist der Zugriff auf die UserInfo eine HTTP-GET-Anfrage:
m_network->get(userInfoApi.createRequest(), this, [this](QRestReply &reply) { if (reply.isSuccess()) { if(auto doc = reply.readJson(); doc && doc->isObject()) qDebug() << doc->object(); // Use the userinfo });
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.