If you want to perform an HTTPS login in C++ with Qt, without using the connect
mechanism (which is usually used for event-driven signal-slot communication), you can handle the network request synchronously or with a separate thread to avoid blocking the main thread.
You can use QNetworkAccessManager::get()
or QNetworkAccessManager::post()
to make the request. However, for this case, since you're handling the login with credentials, you'll probably need to make a POST request with the appropriate data. For synchronous communication, you can block the main thread and wait for the response.
Here's how you can do it synchronously without using connect
:
Synchronous Example (Blocking Call):
cpp
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QSslConfiguration>
#include <QSslSocket>
#include <QJsonDocument>
#include <QJsonObject>
#include <QTimer>
#include <QEventLoop>
#include <QDebug>
int SGServerManage::LoginHttpsServerWithResponse(const QString& sUrl, const QString& sUser, const QString& sPassword, QString& sResponse, QString& sToken) {
// Create a network manager instance
QNetworkAccessManager networkManager(this);
// Construct the URL and create a request
QUrl qUrl(sUrl);
QNetworkRequest request(qUrl);
// Set content type header
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
// Configure SSL settings for the request
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
sslConfig.setProtocol(QSsl::TlsV1_2); // Force TLS 1.2
sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone); // Ignore SSL certificate verification (for self-signed certs)
request.setSslConfiguration(sslConfig);
// Set ciphers for the SSL connection
QList<QSslCipher> ciphers;
ciphers.append(QSslCipher("TLS_AES_128_GCM_SHA256"));
ciphers.append(QSslCipher("TLS_AES_256_GCM_SHA384"));
sslConfig.setCiphers(ciphers);
request.setSslConfiguration(sslConfig);
// Prepare the request body with the user credentials
QJsonObject jsonBody;
jsonBody["username"] = sUser;
jsonBody["password"] = sPassword;
QJsonDocument jsonDoc(jsonBody);
QByteArray jsonData = jsonDoc.toJson(QJsonDocument::Compact);
// Send the POST request and block until the response is received
QNetworkReply* reply = networkManager.post(request, jsonData);
// Wait for the request to finish (blocking)
QEventLoop loop;
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec(); // This will block until the reply is finished
// Handle the reply
int result = -1;
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "Error:" << reply->errorString();
sToken.clear();
sResponse = reply->errorString();
result = -1;
} else {
QByteArray response = reply->readAll();
qDebug() << "Response:" << response;
sResponse = QString::fromUtf8(response);
QJsonDocument jsonDoc = QJsonDocument::fromJson(response);
if (jsonDoc.isObject()) {
QJsonObject jsonObj = jsonDoc.object();
if (jsonObj.contains("token")) {
sToken = jsonObj["token"].toString();
qDebug() << "Token:" << sToken;
result = 0;
} else {
qDebug() << "Token not found in the response.";
sToken.clear();
result = -2;
}
} else {
qDebug() << "Invalid JSON response.";
sToken.clear();
result = -3;
}
}
// Clean up
reply->deleteLater();
return result;
}
cpp
Explanation:
Blocking Behavior: Instead of using
connect
and asynchronous signal-slot connections, I usedQEventLoop
and connected thefinished
signal of theQNetworkReply
to quit the loop. This makes the network request block until a response is received.POST Request: The request is sent using
networkManager.post(request, jsonData)
, and the response is handled synchronously once it's finished.SSL Configuration: I've set the SSL configuration to enforce the use of
TLSv1_2
and ignore SSL verification errors (QSslSocket::VerifyNone
), which is commonly used when working with self-signed certificates. However, for production, you'd want to ensure proper SSL certificate validation.Event Loop: After sending the request, we wait for the response by using a
QEventLoop
. This blocks the thread until thefinished
signal is emitted, indicating the reply is complete.
Thread-Safety Considerations:
Thread Blocking: This approach blocks the calling thread until the network request is finished. If this method is called from the main thread in a GUI application, the UI will freeze while waiting for the server's response. If you need to avoid this, consider moving the request to a worker thread (using
QThread
orQtConcurrent::run
) and still handle it synchronously within that thread.Single Threaded Usage: If the
QNetworkAccessManager
is used in multiple threads, each thread should create its own instance ofQNetworkAccessManager
to ensure thread safety.GUI Freezing: If you use this in a GUI application, remember that the main thread will be blocked. To avoid this, you can either use asynchronous methods with
connect
or offload the work to a separate worker thread.
Moving to Asynchronous Handling (No connect
)
If you don't want to use connect
and still want to perform the task asynchronously, you can handle the response in a worker thread. This allows you to not block the UI while waiting for the response. Here's an example of how to do that:
cpp
// Create a worker thread and run the network request asynchronously in that thread
Would you like an example of handling this in a worker thread or further explanation on that topic? Let me know!