当前位置: 首页 > 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.xdnf.cn/news/1293337.html

相关文章:

  • Pytest项目_day14(参数化、数据驱动)
  • 基于SpringBoot+Vue的智能消费记账系统(AI问答、WebSocket即时通讯、Echarts图形化分析)
  • 挂糊:给食材穿层 “黄金保护衣”
  • 量子安全新纪元:F5发布全新AI驱动的全栈式后量子加密AI安全方案
  • 美团搜索推荐统一Agent之交互协议与多Agent协同
  • 【P21】OpenCV Python——RGB和BGR,HSV和HSL颜色空间,及VScode中报错问题解决
  • 408每日一题笔记 41-50
  • 车载软件架构 --- MCU刷写擦除相关疑问?
  • 前端css学习笔记4:常用样式设置
  • epoll模型解析
  • Socket 套接字的学习--UDP
  • 【H5】禁止IOS、安卓端长按的一些默认操作
  • java中在多线程的情况下安全的修改list
  • Win11和Mac设置环境变量
  • 一键自动化:Kickstart无人值守安装指南
  • [ Mybatis 多表关联查询 ] resultMap
  • 【SpringBoot系列-02】自动配置机制源码剖析
  • RabbitMQ面试精讲 Day 21:Spring AMQP核心组件详解
  • ARM 实操 流水灯 按键控制 day53
  • 部署 Docker 应用详解(MySQL + Tomcat + Nginx + Redis)
  • SQL详细语法教程(二)--DML(数据操作语言)和DQL(数据查询语言)
  • 【IntelliJ IDEA】如何在pom.xml中去除maven中未使用的依赖
  • 存量竞争下的破局之道:品牌与IP的双引擎策略|创客匠人
  • LeetCode 分类刷题:1004. 最大连续1的个数 III
  • PHP imagick扩展安装以及应用
  • 机器学习-Cluster
  • Java项目中地图功能如何创建
  • 机器学习阶段性总结:对深度学习本质的回顾 20250813
  • csp知识基础——贪心算法
  • 类和对象(中下)