web-dev-qa-db-ja.com

python 3.4でHTTP基本認証が機能しない

REST APIにHTTP基本認証を使用してログインしようとしていますが、機能せず、エラーが発生します

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)
12
Vab

次の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)
25
Tobias Ernst

Python 3.x互換性のために更新されました。

requests ライブラリは、この種のリクエストを行うはるかに簡単な方法を提供します。

import requests

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

私自身のテストではこれはうまく機能しますが、urllib.requestを含むソリューション(あなたのようなもの、またはドキュメントの例のコードをそのまま使用する)はAuthentication:ヘッダーの送信に失敗します。

18
larsks

urllib.request.HTTPBasicAuthHandler()はデフォルトでHTTPPasswordMgrを使用します。 HTTPPasswordMgrには、レルムからのパスワードと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の応答コードとサンプルコードを送信した場合、認証は要求されませんでした。

2
Vincent Maillol

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)

もう1つの詳細-独自のコードサンプルを試したところ、「http 401 unauthorized」が返されました。これは、認証に失敗したり、認証がなかったりした場合に予想される応答です。

ただし、http 400の不正なリクエストを受け取ったと主張しているため、URLが間違っているか、他にも問題があると思われます。

2
Anti Veeranna