在QT网络编程中,很多请求都是以HTTP,通过POST/GET方式来完成,简单高效。但是HTTP存在很严重的安全问题,HTTP数据是以明文方式传输,可以很容易被别人监听、抓取到。所以...HTTPS就应运而生了,它的存在就是为了解决HTTP方式传输的不安全问题。本篇文章总结了一个HTTPS加密传输的例子,很有参考意义,谨以此笔记记录下来。
PS: 首先要说明的是,QT是默认使用OpenSSL的。如果JAVA服务器上使用自带JDK生成的自签证书,在低版本的QT中是需要做一步转化工作的。需要将clent.p12
文件,转成cert.pem
证书文件和key.pem
密钥文件,将tomcat.keystore
信任库文件转成tomcat.pem
文件,然后再加载这三个文件,才能进行通信,这里坑了我许久。
在QT 5.1x 版本之后,是可以直接加载JDK 生成的自签证书clent.p12
文件的,本文是以直接加载clent.p12
为例,讲解如何使用QT客户端与JAVA服务器进行通信。准备工作:将ssleay32.dll
libeay32.dll
运行库和client.p12
证书文件与.exe
运行文件放在同一目录下。
设置证书、网络配置及发送请求:
//声明一个 QNetworkAccessManager 对象
QNetworkAccessManager *m_accessManager_Registered;
m_accessManager_Registered = new QNetworkAccessManager(this); //实例化一个对象
//设置连接槽
QObject::connect(m_accessManager_Registered, SIGNAL(finished(QNetworkReply*)), this, SLOT(finishedSlot_Registered(QNetworkReply*)));
//用户登陆验证;
void Widget::on_loginBt_clicked()
{
user_name = ui->userName->text();
user_passwd = ui->passwd->text();
if(user_name.isEmpty() || user_passwd.isEmpty())
{
QMessageBox::warning(this,"错误","用户名、密码不能为空!");
}
else
{
//登陆链接
QString Url = "https://www.example.com/user/login";
QUrl serviceUrl(Url);
QNetworkRequest request_registered(serviceUrl);
// 设置SSL认证方式
QSslConfiguration sslconfig;
sslconfig.setPeerVerifyMode(QSslSocket::VerifyNone); //这里并没有进行严格双向校验,具体设置参数请查看文档,仅作示例(这里是关键)
//传输层安全协议,一般设为TlsV1_0 通用性高,具体要看服务器配置;
sslconfig.setProtocol(QSsl::TlsV1_2);
//sslconfig.setPeerVerifyDepth(1);
//设置本地证书
QFile keyFile("C:/Users/Administrator/Desktop/lock/release/cert/client.p12");
bool openOK = keyFile.open(QIODevice::ReadWrite); //读取本地证书
QSslKey key;
QSslCertificate certs;
QList<QSslCertificate> caCerts;
QByteArray passPhrase = QString("12345678").toLatin1(); //证书密码;
openOK = QSslCertificate::importPkcs12(&keyFile, &key, &certs, &caCerts, passPhrase);
keyFile.close();
//配置SSL
request_registered.setSslConfiguration(sslconfig);
qDebug() << tr("正在进行注册...");
//设置请求头
request_registered.setRawHeader("Accept","*/*");
request_registered.setRawHeader("Connection","keep-alive");
request_registered.setHeader(QNetworkRequest::UserAgentHeader,"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36");
request_registered.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
//首次登陆时候不需要带token
//request_registered.setRawHeader(QByteArray("Authorization"), QByteArray("Token your_token"));
//以表单形式POST
QUrlQuery postData;
postData.addQueryItem("username", user_name);
postData.addQueryItem("password", md5(user_passwd));
qDebug() << tr("注册的用户名:") + user_name + tr("注册的密码:") + md5(user_passwd);
//发起POST请求
QNetworkReply* registered = m_accessManager_Registered->post(request_registered,postData.toString(QUrl::FullyEncoded).toUtf8());
//清除
user_name.clear();
user_passwd.clear();
postData.clear();
}
}
响应请求,解析服务器返回的Json数据
void Widget::finishedSlot_Registered(QNetworkReply *registered)
{
if (registered->error() == QNetworkReply::NoError)
{
// 获取响应信息
QByteArray bytes = registered->readAll(); //读取所有字节;
QJsonParseError jsonError;
//转化为JSON文档
QJsonDocument doucment = QJsonDocument::fromJson(bytes, &jsonError);
// 解析Json error
if (doucment.isObject()) {
QJsonObject obj = doucment.object();
qDebug() << tr("打印obj");
qDebug() << obj;
QJsonValue val;
QJsonValue data_value;
if (obj.contains("message")) {
QString succ_msg = obj.value("message").toString();
ui->textBrowser->appendPlainText(tr("\n")+succ_msg);
qDebug() << tr("打印massage");
qDebug() << succ_msg;
}
if (obj.contains("error")) {
val = obj.value("error");
if ((val.toInt()) == 0) {
ui->textBrowser->appendPlainText("\nUser login succeeded!\n");
QMessageBox::information(this, "成功","登陆成功!");
ui->tripText->setText("用户登陆成功!");
}
}
}
if (jsonError.error != QJsonParseError::NoError) {
ui->textBrowser->insertPlainText(tr("解析json失败"));
qDebug() << QStringLiteral("解析Json失败");
//return;
}
}
else
{
QMessageBox::information(this, "警告","登陆失败!");
qDebug()<<"handle errors here";
QVariant statusCodeV = registered->attribute(QNetworkRequest::HttpStatusCodeAttribute);
//statusCodeV是HTTP服务器的相应码,reply->error()是Qt定义的错误码,可以参考QT的文档
ui->textBrowser->appendPlainText("\n found error ....code:" + statusCodeV.toInt());
//ui->textBrowser->appendPlainText(statusCodeV.toInt());
qDebug( "found error ....code: %d %d\n", statusCodeV.toInt(), (int)registered->error());
qDebug(qPrintable(registered->errorString()));
}
registered->deleteLater();
}
这个例子展示了如何构建QT客户端与JAVA服务器的HTTPS通信,其中关键是本地证书的加载,及设置SSL的步骤,在QT5.1x之后,是支持直接加载.p12
证书的,以前的版本只能通过OpenSS进行转换,因为QT默认是只支持OpenSSL的。在局域网内进行抓包发现,QT客户端发送的数据,是无法看到数据内容的,而服务器正确返回了登陆成功的JSON数据,所以这也验证了HTTPS加密通信已经通过。
版权属于:编码书生
本文链接:https://codess.cc/archives/213.html
所有原创文章采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。
除特别注明,您可以自由的转载和修改,但请务必注明文章来源且不可用于商业目的。
1 条评论
学习了|´・ω・)ノ