基于QWebView开发的浏览器通过需要证书认证网站的方法

来源:互联网 发布:华讯网络薪资 编辑:程序博客网 时间:2024/06/13 08:52

本文由Markdown语法编辑器编辑完成。

1. 前言

现有一款基于QT开发的网络浏览器。已经可以访问一般的网站,如百度,新浪网站等等。但是,当基于该浏览器访问一些内部网站,如需要证书认证的医院HIS系统时,则会提示错误信息(无法通过认证)。

错误提示信息为:
Nginx - 400 Bad Request:
No required SSL certificate was sent.

根据错误提示可知,这是发送HTTP请求时发生了错误,即浏览器客户端在输入URL向服务器端发送Request时,没有附带相应的证书信息,导致客户端未能通过服务器端的安全验证,因此无法获取服务器端的Response.

2. 解决方案:

在需要证书认证的HIS系统中,如果要访问测试环境、预生产环境或生产环境前,都需要先安装证书。本HIS系统需要安装的证书有两个,一个是xxx.crt,另一个是xxx.p12证书,而且第二个证书安装时还需要输入密码,这里假设密码是“123456”。

因此,现在需要解决的问题就是:如何在原来浏览器端在输入URL后发送Request请求前,将相关的证书信息赋予这个Request,以便它能够通过服务器端的安全认证,和服务器端进行正常的数据传输。

QT中与Web服务相关的主要类包括:
QNetworkAccessManager, QRequest, QSslSocket, QSslCertificate, QReply,QSslConfiguration。

在这些类中,核心是QNetworkAccessManager, 关于它的说明参照QT文档:
QNetworkAccessManager: The class allows the application to send network requests and receive replies. The Network Access API is constructed around one QNetworkAccessManager object, which holds the common configuration and setting for the requests it need. It contains the proxy and cache configuration, as well as the signals related to such issues, and reply signals that can be used to monitor the progress of a network operation. One QNetworkAccessManager should be enough for the whole Qt application.
翻译:这个类允许应用程序发送网络请求和接收回应。一个QNetworkAccessManager对象是由一系列网络访问的API函数构成的,包括一般的配置和发送请求时需要的设置。这个对象包括代理和缓存配置以及与这些相关的信号,和能够监视网络操作进度的响应信号。对于一个完整的Qt应用程序,只需要一个QNetworkAccessManager就足够了。

关于这些类之间的相互关系,我觉得可以用以下的结构图来表示:

头文件: NetworkAccessManager.h:

public:    NetworkAccessManager(QObject *parent = 0);    virtual QNetworkReply* createRequest ( Operation op, const QNetworkRequest & req, QIODevice * outgoingData = 0 );private:    bool m_bNeedCertificate;    QString m_crtAddress;    QString m_p12Address;    QString m_p12Password;

源文件:NetworkAccessManager.cpp:

QNetworkReply* NetworkAccessManager::createRequest(Operation op, const QNetworkRequest & req, QIODevice * outgoingData){QNetworkRequest request = req; // copy so we can modify// this is a temporary hack until we properly use the pipelining flags from QtWebkit// pipeline everything! :)request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);//如果支持SSL加密且需要证书认证.if (QSslSocket::supportsSsl() && m_bNeedCertificate){    QFile keyFile(m_p12Address);    bool openOK = keyFile.open(QIODevice::ReadWrite);    QSslKey key;    QSslCertificate certs2;    QList<QSslCertificate> caCertsList;    QByteArray passPhrase = m_p12Password.toLatin1();    openOK = QSslCertificate::importPkcs12(&keyFile, &key, &certs2, &caCertsList, passPhrase);    keyFile.close();    QSslConfiguration sslConfig;    QList<QSslCertificate> certs = QSslCertificate::fromPath(m_crtAddress);    sslConfig.setCaCertificates(certs);    sslConfig.setLocalCertificate(certs2);    sslConfig.setPrivateKey(key);    request.setSslConfiguration(sslConfig);}return QNetworkAccessManager::createRequest(op, request, outgoingData);}

未完待续……

参考链接:

  1. QT解析PKCS#12的代码变更:
    https://git.merproject.org/mer-core/qtbase/commit/1a8788d966da9698b05c1e0bd271d83c5bca9992
  2. 如何在客户端载入证书
    http://www.qtcentre.org/threads/51575-Certificate-How-can-I-import-read-the-client-intermediate-certificate
  3. 如何将一个.p12的证书转化成QSslKey的实体
    https://forum.qt.io/topic/65192/how-to-load-a-p12-key-into-the-qsslkey-object/2
  4. Qt报SSL Error的解决方案
    https://stackoverflow.com/questions/13785862/qt-ssl-error-on-hotmail-com-the-issuer-certificate-of-a-locally-looked-up-certi
原创粉丝点击