urllib2是否支持同时返回基本和摘要认证的服务器

0 投票
2 回答
573 浏览
提问于 2025-04-17 10:17

我正在使用urllib2这个库。

我遇到了一个问题,就是在登录一个服务器时,这个服务器同时支持基本认证和摘要认证。

服务器返回的信息是:

WWW-Authenticate: Digest realm="rets@aus.rets.interealty.com",nonce="c068c3d7d30cc0cd80db4d1c599e6d54",opaque="e75078c8-a825-474b-b101-f8ca2d1627ca",qop="auth"
WWW-Authenticate: Basic realm="rets@aus.rets.interealty.com"

这是我的代码:

passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(realm=None, uri='http://aus.rets.interealty.com', user='user', passwd='pwd')
opener = urllib2.build_opener(urllib2.HTTPDigestAuthHandler(passman))

urllib2.install_opener(opener)

retsRequest= urllib2.Request('http://aus.rets.interealty.com/Login.asmx/Login')
retsRequest.add_header("User-Agent", 'userAgent')
retsRequest.add_header("RETS-Version",'retsVersion')

response=urllib2.urlopen(retsRequest)

print response.read()

我可以通过IE浏览器登录这个服务器,看来IE是使用了摘要认证。

2 个回答

0

最近我有时间来看看这个问题,我觉得我找到了答案。这其实是Python的urllib2库里的一个小bug。在urllib2中:

class AbstractDigestAuthHandler:
    def http_error_auth_reqed(self, auth_header, host, req, headers):
        authreq = headers.get(auth_header, None)
        if self.retried > 5:
            # Don't fail endlessly - if we failed once, we'll probably
            # fail a second time. Hm. Unless the Password Manager is
            # prompting for the information. Crap. This isn't great
            # but it's better than the current 'repeat until recursion
            # depth exceeded' approach <wink>
            raise HTTPError(req.get_full_url(), 401, "digest auth failed",
                            headers, None)
        else:
            self.retried += 1
        if authreq:
            scheme = authreq.split()[0]
            if scheme.lower() == 'digest':
                return self.retry_http_digest_auth(req, authreq)

这里的authreq是:

Basic realm="rets@tra.rets.interealty.com", Digest realm="rets@tra.rets.interealty.com",nonce="512f616ed13813817feddb4fb0ce9e2d",opaque="84f5e814-d38a-44b4-8239-3f5be6ee3153",qop="auth"

authreq.split()[0]的结果会是"Basic",它永远不会是"digest",所以urllib2在进行摘要认证时不会发出第二个请求。

简单来说,urllib2认为在第一次401响应头中只能有一种认证方式。不幸的是,这个服务器返回了两种认证方式。

要解决这个问题,你可以选择使用基本认证,或者使用其他库,比如'requests'。

0

我没有遇到过同样的问题,但曾经惊讶地发现,使用 urllib2.HTTPBasicAuthHandler 的开头实际上会发出两个请求,而不是一个:第一个请求是不带身份验证的,然后如果失败了,第二个请求才会带上身份验证。

这意味着你的情况可能需要三个请求,而第三个请求可能会忘记第二个请求的身份验证信息——最好检查一下。

你可能还需要同时添加 urllib2.HTTPDigestAuthHandlerurllib2.HTTPBasicAuthHandler 到开头中。

撰写回答