在PyQt45中,有什么方法可以用QNetworkAccessManager强制认证吗?

问题描述 投票:1回答:1

在我的实现中,似乎 QNetworkAccessManager 在认证成功后,缓存特定url使用的证书。

随后对同一url的请求使用 不同 凭证会成功,但这只是因为它使用了缓存的凭证而不是新的凭证(即 authenticationRequired 信号没有发出).在(Py)Qt4(也是PyQt 5.6)中是否有办法清除缓存或强制更新缓存的凭证?

(Py)Qt4 (也包括PyQt 5.6)有没有什么方法可以清除缓存或者强制更新缓存的凭证?我是否应该直接删除管理器,然后构建一个新的?还是我做错了什么?

Qt 5提供了一个 clearAccessCache() 方法,但据我所知,Qt 4 没有。

这个小例子说明了这个问题。

import sys
import json
from PyQt4 import QtNetwork, QtGui, QtCore

def show_reply_content(reply):
    content = json.loads(str(reply.readAll()))
    if 'authenticated' in content and content['authenticated']:
        print 'authentication successful for user {}'.format(
            content['user'])
        reply.manager().replies_authenticated += 1

    # Quit when all replies are finished
    reply.deleteLater()
    reply.manager().replies_unfinished -= 1
    if not reply.manager().replies_unfinished:
        print 'number of successful authentications: {}'.format(
            reply.manager().replies_authenticated)
        app.quit()


def provide_credentials(reply, authenticator):
    print 'Setting credentials for {}:\nusername: {}\n' \
          'password: {}\n\n'.format(reply.url(),
                                    reply.credentials['username'],
                                    reply.credentials['password'])
    authenticator.setUser(reply.credentials['username'])
    authenticator.setPassword(reply.credentials['password'])

# Some initialization
app = QtGui.QApplication(sys.argv)
manager = QtNetwork.QNetworkAccessManager()
manager.finished.connect(show_reply_content)
manager.authenticationRequired.connect(provide_credentials)
manager.replies_unfinished = 0
manager.replies_authenticated = 0

# Specify credentials
all_credentials = [dict(username='aap',
                        password='njkrfnq'),
                   dict(username='noot',
                        password='asdfber')]

# url authenticates successfully only for the specified credentials
url = 'http://httpbin.org/basic-auth/{}/{}'.format(
    *all_credentials[1].values())

# Schedule requests
replies = []
for credentials in all_credentials:
    replies.append(
        manager.get(QtNetwork.QNetworkRequest(QtCore.QUrl(url))))

    # Add credentials as dynamic attribute
    replies[-1].credentials = credentials

    manager.replies_unfinished += 1

# Start event loop
app.exec_()

当一个请求成功认证后,下一个请求也成功认证了,尽管它不应该是这样的。

python qt pyqt pyqt4 qnetworkaccessmanager
1个回答
1
投票

原来有几个类似的Qt bug报告还在开放中。QTBUG-16835, QTBUG-30433...

我想应该可以使用 QNetworkRequest.AuthenticationReuseAttribute但我不能让它在使用不同的(有效的)凭证集对同一url进行多个请求时工作。

一个可能的变通方法是忘记所有的 authenticationRequired 信号槽,并添加一个原始头(RFC 7617)到每个请求,确切地说 如上所述.

在本例中,这将意味着删除 authenticationRequired 信号槽连接和更换 manager.get() 部分由以下几行组成 (对于 Python 2.7 和 PyQt4)。

request = QtNetwork.QNetworkRequest(QtCore.QUrl(url))
header_data = QtCore.QByteArray('{}:{}'.format(
    credentials['username'], credentials['password'])).toBase64()
request.setRawHeader('Authorization', 'Basic {}'.format(header_data))
replies.append(manager.get(request))

然而,正如 @ekhumoro 在上面的评论中指出的那样:不知道这有多安全。

© www.soinside.com 2019 - 2024. All rights reserved.