当前位置: 首页 > news >正文

C++QT HTTP与HTTPS的使用方式

上位机与后端传递消息最基础的一个就是登录界面的实现,上位机这边输入用户名和密码传递给服务器检测用户名和密码的准确性。最常见的用法是使用HTTPS,但是本文使用的是HTTP(不要问为什么,问就是业务文档让用HTTP)。

1.HTTP与HTTPS

1)安全性差异

特性HTTPHTTPS
加密❌ 明文传输,数据可被窃听/篡改✅ 使用SSL/TLS加密,防止中间人攻击
数据完整性❌ 无校验机制✅ 通过哈希算法验证数据完整性
身份认证❌ 无法验证服务器身份✅ 通过CA证书验证服务器真实性

2)关键组件对比

组件HTTPHTTPS
默认端口80443
协议处理器QNetworkAccessManager同左,但依赖QSslSocket
证书验证不需要需CA证书(否则需手动忽略错误)
依赖库Qt Network模块Qt Network + OpenSSL库(需额外安装)

3)部署要求

  • HTTP:无需额外配置,但禁止传输敏感数据。

  • HTTPS

    1. 服务器必须配置有效SSL证书(如Let's Encrypt)。

    2. 客户端需链接OpenSSL库(编译Qt时启用-openssl选项)。

    3. 处理证书错误(开发环境可能需要临时忽略)

总结建议

场景推荐协议
公开信息(如新闻)HTTP
登录/支付/API数据传输HTTPS
本地测试HTTP
生产环境必须HTTPS

所以“登录”这一需求需要用的协议应该是HTTPS,可惜没有这个条件,希望下次可以使用到这个协议。因为很多协议光看网上说如何实现可能会有点复杂繁琐,但是实际使用过程中会发现其实蛮简单的。

2.QT中使用

用到的类:

 QNetworkAccessManager* m_pNetworkManager;QNetworkReply* m_pReply = nullptr;

实现流程:构建API端点URL——》构建json请求——》设置HTTP请求——》设置连接超时处理——》发送请求——》处理回复消息

1)初始化

void LoginController::loginUser(const QString& strUserName, QString strPwd, JMLConfig::eUserRole role)
{//输入检查QString strRole = roleToString(role);if (!validateInput(strUserName, strPwd, strRole)){emit loginFailed("Invalid input");return;}//构建API端点URLQUrl apiEndpoint;apiEndpoint.setScheme("http");apiEndpoint.setHost(m_serverIP);apiEndpoint.setPort(m_serverPort);apiEndpoint.setPath("/login");//使用base64加密QString base64Pwd = QString(QByteArray(strPwd.toUtf8()).toBase64());//清除原始密码内存secureClearPassword(strPwd);//JSON请求 QJsonObject jsonPayload;jsonPayload["loginName"] = sanitizeInput(strUserName);jsonPayload["password"] = base64Pwd;QJsonDocument doc(jsonPayload);QByteArray data = doc.toJson();//设置HTTP请求QNetworkRequest request(apiEndpoint);request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");request.setRawHeader("User-Agent", "Industrial-Secure-Client/2.0");//设置超时处理QTimer* timeoutTimer = new QTimer(this);timeoutTimer->setSingleShot(true);timeoutTimer->start(15000);connect(timeoutTimer, &QTimer::timeout, this, [=]() {if (m_pReply && m_pReply->isRunning()) {m_pReply->abort();emit loginFailed("连接超时 (15秒)");timeoutTimer->deleteLater();}});//发送请求m_pReply = m_pNetworkManager->post(request, data);connect(m_pReply, &QNetworkReply::finished, this, [this]() {handleLoginResponse(m_pReply);});connect(m_pReply, &QNetworkReply::finished, timeoutTimer, &QObject::deleteLater);
}

这个api需要与后端协商好,一般都是后端做好接口之后主动提供接口文档,可以对照文档来写接收信息的内容。

一开始想要判定IP地址和端口的可达性,可以使用QTcpSocket来判定,或者WIN+R输入cmd,输入telent IP地址 端口号来判定这个ip和端口是否能通信。

QTcpSocket testSocket;
testSocket.connectToHost("127.0.0.0", 8080);
if (testSocket.waitForConnected(3000)) {//qDebug() << "服务器可达";emit loginSuccess("0", "服务器可达");
}
else {//qDebug() << "无法连接服务器:" << testSocket.errorString();emit loginFailed(testSocket.errorString());return;
}

2)处理回复

void LoginController::handleLoginResponse(QNetworkReply* reply)
{m_pReply = nullptr;//处理网络错误if (reply->error() != QNetworkReply::NoError) {if (reply->error() == QNetworkReply::OperationCanceledError) {emit loginFailed("连接超时");}else {emit loginFailed("网络错误: " + reply->errorString());}reply->deleteLater();return;}//处理HTTP状态码int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();if (statusCode != 200) {emit loginFailed(QString("服务器错误: HTTP %1").arg(statusCode));reply->deleteLater();return;}//安全读取响应QByteArray response = reply->readAll();if (response.size() > 4096) { //防止过大响应导致内存耗尽emit loginFailed("服务器响应异常");reply->deleteLater();return;}//解析JSON响应QJsonParseError parseError;QJsonDocument doc = QJsonDocument::fromJson(response, &parseError);if (parseError.error != QJsonParseError::NoError){emit loginFailed("服务器响应格式错误");reply->deleteLater();return;}QJsonObject json = doc.object();//验证响应结构if (!json.contains("success") || !json.contains("result")) {emit loginFailed("服务器响应格式错误");reply->deleteLater();return;}//处理登录结果if (json["success"].toBool() == true){//获取用户信息用于展示QJsonObject result = json["result"].toObject();if (result.isEmpty()){emit loginFailed(QStringLiteral("没有用户对应信息"));reply->deleteLater();return;}QString userType = result["userType"].toString();QString userName = result["userName"].toString();emit loginSuccess(userType, userName);}else {QString errorMsg = json["message"].toString();emit loginFailed(errorMsg);}reply->deleteLater();
}

3)密码加密

这个应该蛮简单的,我这里用的是base64加密,最简单的加密方式。之前还用过hash加密,产生随机盐值然后进行加密。稍微记录一下,毕竟真的是太久不用就忘了。

QString LoginController::generateRandomSalt() const
{//盐值的目的://使相同密码产生不同哈希值//确保不同用户的相同密码哈希不同//强制攻击者为每个用户单独计算QByteArray salt;salt.resize(16);QRandomGenerator* generator = QRandomGenerator::system();for (auto i = 0; i < salt.size(); ++i){salt[i] = generator->generate() % 256;}return salt.toBase64();
}QString LoginController::hashPassword(const QString& strPwd, const QString& strSalt)
{QByteArray passwordData = strPwd.toUtf8();QByteArray saltData= strSalt.toUtf8();//参数:密码,盐,迭代次数,输出长度,哈希算法QByteArray hashed = QCryptographicHash::hash(passwordData + saltData,QCryptographicHash::Sha256);return hashed.toHex();
}

http://www.lryc.cn/news/619349.html

相关文章:

  • 【网络安全测试】OWASP ZAP web安全测试工具使用指导及常用配置(有关必回)
  • Spring事务管理实战:从注解到进阶
  • Spring 源码学习(十)—— DispatcherServlet
  • 【一步AI】模型压缩:减小模型体积与计算量
  • YOLOv8 级联检测:在人脸 ROI 内检测眼镜(零改源码方案)
  • 第十六届蓝桥杯青少组C++省赛[2025.8.9]第二部分编程题(1 、庆典队列)
  • Excel怎么筛选重复项?【图文详解】查找/删除重复项?查找重复项公式?如何去重?
  • [QtADS]解析demo.pro
  • HarmonyOS NDK的JavaScript/TypeScript与C++交互机制
  • Electron自定义菜单栏及Mac最大化无效的问题解决
  • XML头部声明发送者信息的实现方法
  • C# 微软依赖注入 (Microsoft.Extensions.DependencyInjection) 详解
  • CV 医学影像分类、分割、目标检测,之【肝脏分割】项目拆解
  • windows常用的快捷命令
  • 机器学习实战·第三章 分类(2)
  • docker 容器内编译onnxruntime
  • git clone 支持在命令行临时设置proxy
  • CV 医学影像分类、分割、目标检测,之【腹腔多器官语义分割】项目拆解
  • 何解决PyCharm中pip install安装Python报错ModuleNotFoundError: No module named ‘json’问题
  • Video_AVI_Packet(2)
  • 基于RTSP|RTMP低延迟视频链路的多模态情绪识别系统构建与实现
  • 日志数据链路的 “搬运工”:Flume 分布式采集的组件分工与原理
  • 进阶向:Python编写自动化邮件发送程序
  • Jenkins一直无法启动,怎么办?
  • 论文分享 | Flashboom:一种声东击西攻击手段以致盲基于大语言模型的代码审计
  • 守拙以致远:个人IP的长青之道|创客匠人
  • Hive 创建事务表的方法
  • 自建知识库,向量数据库 体系建设(四)之文本向量与相似度计算——仙盟创梦IDE
  • java中list的api详细使用
  • 无人机航拍数据集|第15期 无人机人员目标检测YOLO数据集4923张yolov11/yolov8/yolov5可训练