HTTP基本身份验证在python 3.4中不起作用

时间:2015-04-17 20:23:43

标签: python http-basic-authentication

我正在尝试使用HTTP基本身份验证登录REST API,但它无法正常运行并提供错误

HTTP error 400: Bad Request

这是我的代码:

import urllib.parse
import urllib.request
import urllib.response

# create an authorization handler
#auth_handler = urllib.request.HTTPPasswordMgrWithDefaultRealm()
auth_handler = urllib.request.HTTPBasicAuthHandler()


# Add the username and password.
# If we knew the realm, we could use it instead of None.

userName = "username"
passWord  = "pass"
top_level_url = "http URL"
auth_handler.add_password(None, top_level_url, userName,passWord)


# create "opener" (OpenerDirector instance)
opener = urllib.request.build_opener(auth_handler)



# Install the opener.
# Now all calls to urllib.request.urlopen use our opener.
urllib.request.install_opener(opener)

# use the opener to fetch a URL
try:
    result = opener.open(top_level_url)
    #result = urllib.request.urlopen(top_level_url)
    messages = result.read()
    print (messages)  
except IOError as e:
    print (e)

5 个答案:

答案 0 :(得分:23)

以下python3代码将起作用:

import urllib.request
import base64
req = urllib.request.Request(download_url)

credentials = ('%s:%s' % (username, password))
encoded_credentials = base64.b64encode(credentials.encode('ascii'))
req.add_header('Authorization', 'Basic %s' % encoded_credentials.decode("ascii"))

with urllib.request.urlopen(req) as response, open(out_file_path, 'wb') as 
out_file:
    data = response.read()
    out_file.write(data)

答案 1 :(得分:16)

requests库提供了一种更简单的方法来提出这种请求:

import requests

response = requests.get('http://service.example.com',
                        auth=requests.auth.HTTPBasicAuth(
                          'username',
                          'password'))
print response.text

在我自己的测试中,这很好,而涉及urllib.request的解决方案(与您的一样,或者从文档中的示例逐字使用代码)将无法发送Authentication:标题。 / p>

答案 2 :(得分:2)

我也会使用larsks推荐的请求库,它使HTTP请求变得更加容易。

那就是说,这是一个使用urllib的工作代码示例

import urllib.parse
import urllib.request
import urllib.response

username = "my_username"
password  = "my_password"
top_level_url = "URL"

# create an authorization handler
p = urllib.request.HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, top_level_url, username, password)

auth_handler = urllib.request.HTTPBasicAuthHandler(p)

opener = urllib.request.build_opener(auth_handler)

urllib.request.install_opener(opener)

try:
    result = opener.open(top_level_url)
    messages = result.read()
    print (messages)
except IOError as e:
    print (e)

另一个细节 - 我尝试了你自己的代码示例,然后我回来了#34; http 401未授权",这将是auth失败或丢失时的预期响应。

但是你声称你收到了http 400错误的请求,这导致我认为你有错误的网址或者还有其他一些问题

答案 3 :(得分:2)

默认情况下,

urllib.request.HTTPBasicAuthHandler()使用HTTPPasswordMgrHTTPPasswordMgr包含一个包含来自领域和top_level_url的密码的地图。

执行请求时,服务器返回401.返回的HTTP标头包含:

Www-Authenticate: Basic realm="a-value"

返回领域的HTTPPasswordMgr次搜索(用户,密码)和新请求将与(用户,密码)一起发送。

当你写:

auth_handler = urllib.request.HTTPBasicAuthHandler()
# Never use None to realm parameter.
auth_handler.add_password(None, top_level_url, userName,passWord)

您希望服务器发送None域(但不可能)。如果您希望服务器在Www-Autheader中发送空域,则应使用

auth_handler.add_password('', top_level_url, userName,passWord)

您可以使用HTTPPasswordMgrWithDefaultRealm代替HTTPPasswordMgr来忽略返回的领域:

auth_handler = urllib.request.HTTPBasicAuthHandler(
    urllib.request.HTTPPasswordMgr()
)
auth_handler.add_password(None, top_level_url, userName,passWord))

如果您的服务器使用您的示例代码向您发送400响应代码,则不会询问身份验证。

答案 4 :(得分:2)

以下代码来自https://docs.python.org/3.1/howto/urllib2.html,但在请求时不发送身份验证信息。

# create a password manager
password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()

# Add the username and password.
# If we knew the realm, we could use it instead of None.
top_level_url = "http://example.com/foo/"
password_mgr.add_password(None, top_level_url, username, password)

handler = urllib.request.HTTPBasicAuthHandler(password_mgr)

# create "opener" (OpenerDirector instance)
opener = urllib.request.build_opener(handler)

# use the opener to fetch a URL
opener.open(a_url)

# Install the opener.
# Now all calls to urllib.request.urlopen use our opener.
urllib.request.install_opener(opener)

HTTPPasswordMgrWithDefaultRealm更改为HTTPPasswordMgrWithPriorAuth 并在通话is_authenticated=True为我工作时传递password_mgr.add_password

password_mgr = urllib.request.HTTPPasswordMgrWithPriorAuth()
password_mgr.add_password(None, url, username, password, is_authenticated=True)