urllib2:如何通过AuthHandler向* initial *请求添加标头的正确方法?

时间:2014-02-08 15:36:04

标签: python http urllib2 basic-authentication urllib

这可能是一个愚蠢的问题,但我找不到如何创建AuthHandler的方法,它会在FIRST请求中添加Authorization标头。我在urllib2.py中唯一看到的是各种http_error处理程序,它将Authorization标头添加到处理错误的 ADDITIONAL 请求中。

但是,在查看http://www.ietf.org/rfc/rfc2617.txt第2节时,我看到了这一点:

  

客户端可以抢先发送相应的授权标头,其中包含该空间中的资源请求,而不会从服务器收到其他质询。

真的有很多服务器(例如,api.github.com)希望授权标头与初始请求一起发送,实际上他们broke因此而不是401而是发送404状态代码。

任何人都知道如何将*AuthHandler子类化,以便在初始请求中添加标题?

顺便说一句,由于与该问题无关的许多原因,不,python-requests不是答案。请不要浪费我的时间来暗示它。答案必须只在stdlib的上下文中。

1 个答案:

答案 0 :(得分:1)

好的,所以最后它是http_request方法。因此,例如,这是向GitHub添加新错误的脚本:

from base64 import standard_b64encode
import http.client
from urllib.request import (HTTPBasicAuthHandler, Request, HTTPSHandler,
                            build_opener, HTTPPasswordMgrWithDefaultRealm)
import json
import os
from configparser import ConfigParser
http.client.HTTPConnection.debuglevel = 1


class HTTPBasicPriorAuthHandler(HTTPBasicAuthHandler):
    handler_order = 400

    def http_request(self, req):
        if not req.has_header('Authorization'):
            user, passwd = self.passwd.find_user_password(None,
                                                          req.get_host())
            credentials = '{0}:{1}'.format(user, passwd).encode()
            auth_str = standard_b64encode(credentials).decode()
            req.add_unredirected_header('Authorization',
                                        'Basic {}'.format(auth_str.strip()))
        return req

    https_request = http_request

cp = ConfigParser()
cp.read(os.path.expanduser('~/.githubrc'))

# That configuration file should look something like
# [github]
# user=mylogin
# password=myveryverysecretpassword

gh_user = cp.get('github', 'user')
gh_passw = cp.get('github', 'password')
repo = 'reponame'

pwd_manager = HTTPPasswordMgrWithDefaultRealm()
pwd_manager.add_password(None, 'https://api.github.com', gh_user, gh_passw)
auth_prior_handler = HTTPBasicPriorAuthHandler(pwd_manager)
verbose_handler = HTTPSHandler(debuglevel=2)

opener = build_opener(verbose_handler, auth_prior_handler)

# Be careful that there is no slash in the end of the URL
gh_url = "https://api.github.com/repos/{0}/{1}/issues".format(gh_user, repo)

create_data = {
    'title': 'Testing bug summary',
    'body': '''This is a testing bug. I am writing here this stuff,
            just to have some text for body.''',
    'labels': ['somelabel']
}

gh_req = Request(gh_url, json.dumps(create_data).encode('utf8'))

handler = opener.open(gh_req)

print(handler.getcode())
print(handler)

实际上,现在我相信这个问题的答案是使用我的urllib2_prior_auth包。