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
connectand asynchronous signal-slot connections, I usedQEventLoopand connected thefinishedsignal of theQNetworkReplyto 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_2and 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 thefinishedsignal 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
QThreadorQtConcurrent::run) and still handle it synchronously within that thread. -
Single Threaded Usage : If the
QNetworkAccessManageris used in multiple threads, each thread should create its own instance ofQNetworkAccessManagerto 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
connector 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!