c++ - 无法使用 C++、Qt 和 Betfair API-NG 使用 SSL 证书登录

标签 c++ qt https ssl-certificate betfair

我正在使用 Qt 用 C++ 编写一个新的 Betfair 机器人,但我遇到了登录过程的第一个障碍。在大量阅读之后,我决定使用 QNetworkAccessManager,这就是我目前拥有的:

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    BetfairManager bet_man;
    QNetworkAccessManager *manager = new QNetworkAccessManager();
    QObject::connect(manager, SIGNAL(finished(QNetworkReply*)),
                        &bet_man,SLOT(replyFinished(QNetworkReply*)));
    QObject::connect(manager,SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
                     &bet_man,SLOT(replySSLErrors(QNetworkReply*,QList<QSslError>)));
    QObject::connect(manager,SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
                     &bet_man,SLOT(replyAuthenticationRequired(QNetworkReply*,QAuthenticator*)));
    QObject::connect(manager,SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&,QAuthenticator*)),
                     &bet_man,SLOT(replyProxyAuthenticationRequired(const QNetworkProxy&,QAuthenticator*)));
    QNetworkRequest request;


    QByteArray payload("username=myusername&password=mypassword");
    QString url("https://identitysso.betfair.com/api/certlogin");
    QSslConfiguration config;
    QString pemfile("../../client-2048.pem");
    QFile file(pemfile);
    if(!file.exists()) {
       qWarning("Filename %s doesn't exists.", qPrintable(pemfile));
    }

    if(!file.open(QIODevice::ReadOnly)) {
        qWarning("Cannot open filename %s.", qPrintable(pemfile));
    }
    QByteArray data = file.readAll();

    QSslCertificate sslcert(data, QSsl::Pem);
    if(sslcert.isNull()) {
        qWarning("The certificate has no content.");
    }

    config.setLocalCertificate(sslcert);
    request.setSslConfiguration(config);
    request.setUrl(url);
    request.setRawHeader("X-Application","mykey");
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");

    manager->post(request,payload);

    return a.exec();
}

BetfairManager 类只是我创建的一个虚拟类,用于为 QNetworkAccessManager 信号提供插槽 - 它们只是将一些调试信息转储到屏幕上以查看什么信号已经发出。

当我运行上面的代码时,我看到 QNetworkAccessManager::finished() 信号已经触发,但我得到一个空的响应——甚至没有任何 HTTP header 。

当我通过注释掉该行来停止设置证书时

request.setSslConfiguration(config);

我收到回复

"{"loginStatus":"CERT_AUTH_REQUIRED"}"

这不足为奇,但表明我在我的请求中传递了正确的参数,因此我确信问题在于我的证书传递机制/使用 Qt 类创建。

我已经根据 betfair 文档创建了 .pem 文件(它说通过附加生成的 .crt 和 .key 文件来创建它)并且我知道它们很好,因为我还有一个 Python 机器人可以完美地使用相同的文件。

我是 Qt 的新手,不是 SSL 专家,我觉得我在这里缺少一些基本的东西。

如果它在这里有用是我的 Python 等效代码,它使用 urllib2 包完美运行

un = "myusername";
pw = "mypassword";
app_key = 'mykey'

payload = 'username=' + un + '&password=' + pw
login_headers = {'X-Application': app_key, 'Content-Type': 'application/x-www-form-urlencoded'}
resp = requests.post('https://identitysso.betfair.com/api/certlogin', data=payload, cert=('client-2048.crt', 'client-2048.key'), headers=login_headers)

我正在 Ubuntu 14.04 上使用 Qt 5.2.1 开发

最佳答案

当您想使用客户端证书通过 SSL 连接登录时,您需要另外指定客户端的私钥。证书基本上只是一个公钥,由其他人检查。当您可以向服务器证明您也拥有证书的私钥时,就会授予访问权限。

您可以使用以下方法做到这一点:

// get certData and keyData from files

QSslConfiguration config;

QSslCertificate sslcert(certData, QSsl::Der);
config.setLocalCertificate(sslcert);

QSslKey privkey(keyData, QSsl::Rsa, QSsl::Der, QSsl::PrivateKey, "myKeyPassword")
config.​setPrivateKey(privkey);

当您的原始文件 client-2048.crtclient-2048.key 都是二进制文件时,它们很可能以 DER 格式存储。在这种情况下,您可以像上面那样指定输入格式,不需要进行任何转换。

关于c++ - 无法使用 C++、Qt 和 Betfair API-NG 使用 SSL 证书登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27850890/

相关文章:

c++ - 如何通过QGraphicsProxy调整QGraphicScene中添加的QWidget的大小?

qt - QDir::tempPath() 与 QStandardPaths::writableLocation()

ssl - Golang 中的 TLS 连接问题

c++ - 在输出文件 C++ 中搜索整数

c++ - filter2d() 与 gaussian kernel 和 GaussianBlur() 的区别

c++ - 错误 C3861 : 'decrypt' not found even with function in header

apache - NGINX -> Varnish 负载平衡器 -> Apache SSL 连接 = 错误请求

c++ - 命名管道,服务器问题

Qt 5 : Debug\release and Release\debug directories

java - 在 Spring Boot 中存储证书的最佳做法是什么?