Zum Hauptinhalt springen

Sign users in to a Qt desktop app

This guide explains how to run the Casdoor example for Qt and how to add the same sign-in flow to your own C++ app with casdoor-cpp-sdk. The example shows the Casdoor sign-in page in an embedded browser.


Learning outcomes​

  • Configure and run the example app.
  • Create a Casdoor client in C++.
  • Open the sign-in page, catch the callback, and verify the token.

What you need​

  • Qt 6 with the Qt WebEngine module. On Windows, use the MSVC build of Qt.
  • CMake 3.16 or later and a C++17 compiler
  • OpenSSL 1.1.1 or 3.x
  • An application in Casdoor

CMake downloads casdoor-cpp-sdk when it configures the project. You don't install the SDK yourself.

Sample code​


Run the example​

  1. In the Casdoor admin console, add http://localhost:8080/callback to the Redirect URLs of the application. Nothing has to listen on that port, because the example catches the redirect inside its embedded browser.

  2. Clone casdoor-cpp-qt-example and set the following values:

    NameBeschreibungDatei
    kCasdoorEndpointYour Casdoor server URL, like http://localhost:8000config.h
    kClientIdDie Client-ID Ihrer Casdoor-Anwendungconfig.h
    kClientSecretDas Client-Geheimnis Ihrer Casdoor-Anwendungconfig.h
    kCertificateThe public certificate of the cert your application usesconfig.h
    kOrganizationNameDer Name Ihrer Casdoor-Organisationconfig.h
    kApplicationNameDer Name Ihrer Casdoor-Anwendungconfig.h
    kRedirectUriThe redirect URL, http://localhost:8080/callbackconfig.h
  3. Build and start the app.

    • In Qt Creator: Open CMakeLists.txt and press Ctrl + R.

    • On the command line:

      cmake -S . -B build -DCMAKE_PREFIX_PATH=/path/to/Qt/6.x/<compiler>
      cmake --build build
      ./build/casdoor-cpp-qt-example

      On Windows, if CMake can't find OpenSSL, add -DOPENSSL_ROOT_DIR="C:/Program Files/OpenSSL-Win64".

  4. In the app window, click Sign In.

    Main window of the example app

    The Casdoor sign-in page opens in a window.

    Casdoor sign-in window

  5. Sign in. The app shows the profile of the user.

    User profile in the example app

Recording of the complete sign-in flow

Add sign-in to your app​

Create the client​

#include <casdoor/casdoor.h>

casdoor::Config config;
config.endpoint = kCasdoorEndpoint;
config.client_id = kClientId;
config.client_secret = kClientSecret;
config.certificate = kCertificate;
config.organization_name = kOrganizationName;
config.application_name = kApplicationName;

casdoor::Client casdoor(config);

Open the sign-in window​

Generate a random state, build the sign-in URL, and load it in the embedded browser:

// A random state ties the callback to this sign-in attempt
m_state = QUuid::createUuid().toString(QUuid::WithoutBraces);
std::string signinUrl = m_casdoor.GetSigninUrl(kRedirectUri, m_state.toStdString());

m_webview->load(QUrl(QString::fromStdString(signinUrl)));
m_webview->show();

Catch the callback​

After the user signs in, Casdoor redirects to the redirect URL with code and state. A subclass of QWebEnginePage stops the embedded browser from loading that URL and hands the URL to the app:

bool CallbackPage::acceptNavigationRequest(const QUrl& url, NavigationType type, bool isMainFrame)
{
if (isMainFrame && url.adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment) == m_redirectUri) {
emit callbackReceived(url);
return false;
}
return QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame);
}

Get the user from the code​

Check state, exchange the code for a token, and verify the token with the certificate:

QUrlQuery query(url);
QString code = query.queryItemValue("code", QUrl::FullyDecoded);
QString state = query.queryItemValue("state", QUrl::FullyDecoded);
if (code.isEmpty() || state != m_state) {
return;
}

try {
casdoor::Token token = m_casdoor.GetOAuthToken(code.toStdString());
casdoor::Claims claims = m_casdoor.ParseJwtToken(token.access_token);
// claims.name, claims.display_name, claims.email, claims.owner, claims.payload ...
} catch (const casdoor::Error& e) {
QMessageBox::warning(this, "Sign in failed", e.what());
}

ParseJwtToken throws casdoor::Error if the signature, the expiry, or the audience of the token is invalid.

Next steps​

casdoor-cpp-sdk also refreshes tokens and manages users. See the casdoor-cpp-sdk repository.

See also​