Qt QWebsocket实现SSL后台服务程序 和微信小程序连接使用
——Qt QWebsocket SSL wss 微信小程序
前言
微信小程序是不支持https和wss以外的远程通信接口的,这给很多希望使用小程序实现与自建非web类服务后台程序通信的小伙伴带来很多不便,比如我们在云服务器端使用Qt开发了一个服务器应用,用来提供数据库服务和嵌入式终端控制等功能。 嵌入式终端由于性能受限,一般很少直接运行https或wss协议,往往采用外挂一个tcp或udp透传模块实现远程网络连接传递数据,当控制端使用app实现时就很容易了,直接tcp或udp搞定,但如果向通过微信小程序来做控制端,就必须得用https或wss,这是微信的强制要求,为了提供更安全的服务。
SSL配置
网络上对基于web服务器和小程序进行安全通信的例子很多,但基本都是基于这种B/S【browser/server】架构的,在服务器端进行IIS、Apache、Njinx等的配置就能实现。但对于刚才讲的C/S【client/server】架构的应用,该怎么实现呢?
- 首先
每个微信小程序需要事先设置通讯域名,小程序只可以跟指定的域名进行网络通信。包括普通 HTTPS 请求(wx.request)、上传文件(wx.uploadFile)、下载文件(wx.downloadFile) 和 WebSocket 通信(wx.connectSocket)。
上面讲的通信域名在哪里设置呢?见下图,在小程序开发管理的开发设置中,注意填入的要是域名,不能是公网IP,虽然公网ip在调试时是可以的,但发布后就被限制使用了。还有,只允许443端口,不能改成其他的,设置框和js代码中的也要一致,要么都不带端口号,要么都带端口号443。
- 然后
小程序必须使用 HTTPS/WSS 发起网络请求。请求时系统会对服务器域名使用的 HTTPS 证书进行校验,如果校验失败,则请求不能成功发起。
这里的https证书就是指ssl或者ca证书,很多教程教大家使用openssl生成自签名证书来调试,这种自签名证书只能用来调试测试或者内部局域网使用,如果小程序是正常发布在互联网使用,那就必须使用正规证书颁发机构(CA)购买的签名证书,一般云服务器提供商都会有便捷申请的服务。 获得的证书一般都包含一个根证书、一个中间证书和一个key密钥文件,像腾讯云申请的证书就会按照不同的服务器类型提供相应的证书,大同小异,证书内容都是一样的。 以下这些分类也都是针对web服务应用的,像咱们现在说的C/S架构就不用分这么细了,因为都是在C++程序里创建的通信服务,压根用不上单独配置下面的web服务器。对于我们来说,直接用和apache一样的证书文件就好,即2个.crt证书文件和1个.key密钥文件。名字里带root的crt为根证书,另一个叫中间证书,或leaf Certificate。
.csr文件:证书签名请求文件。 .key文件是证书私钥文件,如果申请证书时没有选择系统创建CSR,则没有该文件。请您保存好该私钥文件。 .crt文件:证书文件,一般包含两段内容。如果是Apache服务器,会将证书文件拆分成_public.crt(证书文件)和_chain.crt(证书链或中间证书文件)。 .pem文件:证书文件,一般包含两段内容。Nginx证书会使用扩展名文件,在阿里云SSL证书中与.crt文件一样。说明:.crt扩展名的证书文件采用Base64-encoded的PEM格式文本文件,可根据需要,修改成.pem等扩展名。 .pfx文件:一般适合Tomcat/IIS服务器。每次下载都会产生新密码,该密码仅匹配本次下载的证书。如果需要更新证书文件,同时也要更新密码。
- 接下来,确认以下对证书要求:
HTTPS 证书必须有效; 证书必须被系统信任,即根证书被已系统内置 部署 SSL 证书的网站域名必须与证书颁发的域名一致 证书必须在有效期内 证书的信任链必需完整(需要服务器配置) iOS 不支持自签名证书; iOS 下证书必须满足苹果 App Transport Security (ATS) 的要求; TLS 必须支持 1.2 及以上版本。部分旧 Android 机型还未支持TLS 1.2,请确保 HTTPS 服务器的 TLS 版本支持 1.2 及以下版本;
上面的红色字体是关键,但和c++代码有关,所以放在后面一起说。 先来说说如何判断自己的证书文件是否配置的合乎要求,有这个一个网站https://myssl.com/,输入你的域名就可以自动检测给出报告。当然,在检测时,你的c++服务器程序要运行哦。
- 重点来了,很多朋友在折腾完一圈操作后,在真机调试小程序是均以失败告终,常见的报错如下:
errMsg: “exception onOpen fail code:8, msg:TLS handshake failed”
握手失败!!! 官方给出的解答是因为证书有问题,要重新配置,然后就没有然后了。报这个错误的同时,上面讲的证书检测结果中也会有一条提示:“证书链不完整”!!!
QSslConfiguration sslConfiguration;
QFile certFile (QStringLiteral ("localhost.crt"));
QFile keyFile (QStringLiteral ("localhost.key"));
certFile.open (QIODevice::ReadOnly);
keyFile.open (QIODevice::ReadOnly);
QSslCertificate certificate (&certFile, QSsl::Pem);
QSslKey sslKey (&keyFile, QSsl::Rsa, QSsl::Pem);
certFile.close ();
keyFile.close ();
sslConfiguration.setPeerVerifyMode (QSslSocket::VerifyNone);
sslConfiguration.setLocalCertificate (certificate);
sslConfiguration.setPrivateKey (sslKey);
sslConfiguration.setProtocol (QSsl::TlsV1SslV3);
this->setSslConfiguration (sslConfiguration);
发现没有,配置ssl时只有一个crt和一个key,然后setLocalCertificate。问题就出在这里,前面说的证书链可是三个文件,2个crt和1个key,怎么改呢?
QSslConfiguration sslConfiguration;
QFile leafcertFile (QStringLiteral ("leaf.crt"));
QFile rootcertFile (QStringLiteral ("root.crt"));
QFile keyFile (QStringLiteral ("localhost.key"));
leafcertFile.open (QIODevice::ReadOnly);
rootcertFile.open (QIODevice::ReadOnly);
keyFile.open (QIODevice::ReadOnly);
QSslCertificate leafcertificate (&leafcertFile, QSsl::Pem);
QSslCertificate rootcertificate (&rootcertFile, QSsl::Pem);
QSslKey sslKey (&keyFile, QSsl::Rsa, QSsl::Pem);
leafcertFile.close ();
rootcertFile.close ();
keyFile.close ();
QList<QSslCertificate> localChain;
localChain.append(leafcertificate);
localChain.append(rootcertificate);
sslConfiguration.setPeerVerifyMode (QSslSocket::VerifyNone);
sslConfiguration.setLocalCertificateChain(localChain);
sslConfiguration.setPrivateKey (sslKey);
sslConfiguration.setProtocol (QSsl::TlsV1_0OrLater);
this->setSslConfiguration (sslConfiguration);
然后,你再检测,证书链完整了。小程序能跑了!大功告成,欢喜ing… 来来来 看看效果😁😁😁
号外
小程序调试中要注意 js中wss之url格式:
this.globalData.websk = wx.connectSocket({
url: 'wss://www.xxx.xxx'
})
刚配置好直接运行可能会报错,“域名不在以下合法域名列表中。。。”诸如此类,此时要打开微信开发者工具,刷新以下项目配置,显示出你配置的域名后就正常了。
|