我正在使用 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.crt
和 client-2048.key
都是二进制文件时,它们很可能以 DER 格式存储。在这种情况下,您可以像上面那样指定输入格式,不需要进行任何转换。
关于c++ - 无法使用 C++、Qt 和 Betfair API-NG 使用 SSL 证书登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27850890/