[python] Python urllib2 기본 인증 문제
업데이트 : Lee의 의견에 따라 내 코드를 정말 간단한 스크립트로 압축하고 명령 줄에서 실행하기로 결정했습니다.
import urllib2
import sys
username = sys.argv[1]
password = sys.argv[2]
url = sys.argv[3]
print("calling %s with %s:%s\n" % (url, username, password))
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, url, username, password)
urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(passman)))
req = urllib2.Request(url)
f = urllib2.urlopen(req)
data = f.read()
print(data)
불행히도 여전히 Authorization
헤더를 생성하지 않습니다 (Wireshark 당) 🙁
urllib2를 통해 기본 AUTH를 보내는 데 문제가 있습니다. 이 기사를 살펴보고 예제를 따랐습니다. 내 코드 :
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, "api.foursquare.com", username, password)
urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(passman)))
req = urllib2.Request("http://api.foursquare.com/v1/user")
f = urllib2.urlopen(req)
data = f.read()
wireshark를 통해 Wire에서 다음을보고 있습니다.
GET /v1/user HTTP/1.1
Host: api.foursquare.com
Connection: close
Accept-Encoding: gzip
User-Agent: Python-urllib/2.5
curl을 통해 요청을 보낼 때와 비교하여 Authorization이 전송되지 않은 것을 볼 수 있습니다. curl -u user:password http://api.foursquare.com/v1/user
GET /v1/user HTTP/1.1
Authorization: Basic =SNIP=
User-Agent: curl/7.19.4 (universal-apple-darwin10.0) libcurl/7.19.4 OpenSSL/0.9.8k zlib/1.2.3
Host: api.foursquare.com
Accept: */*
어떤 이유로 내 코드가 인증을 보내지 않는 것 같습니다. 누구든지 내가 놓친 것을 볼 수 있습니까?
감사
-사이먼
답변
문제는 HTTP 표준에 따라 Python 라이브러리가 먼저 인증되지 않은 요청을 보낸 다음 401 재시 도로 응답 한 경우에만 올바른 자격 증명이 전송된다는 것입니다. Foursquare 서버가 “완전히 표준 인증”을 수행하지 않으면 라이브러리가 작동하지 않습니다.
헤더를 사용하여 인증을 시도하십시오.
import urllib2, base64
request = urllib2.Request("http://api.foursquare.com/v1/user")
base64string = base64.b64encode('%s:%s' % (username, password))
request.add_header("Authorization", "Basic %s" % base64string)
result = urllib2.urlopen(request)
당신과 같은 문제가 있었고이 스레드에서 해결책을 찾았습니다 : http://forums.shopify.com/categories/9/posts/27662
답변
( https://stackoverflow.com/a/24048772/1733117 에서 복사-붙여 넣기 / 조정 ).
먼저 urllib2.BaseHandler
또는의 하위 클래스 urllib2.HTTPBasicAuthHandler
를 만들고 http_request
각 요청에 적절한 Authorization
헤더를 갖도록 구현할 수 있습니다 .
import urllib2
import base64
class PreemptiveBasicAuthHandler(urllib2.HTTPBasicAuthHandler):
'''Preemptive basic auth.
Instead of waiting for a 403 to then retry with the credentials,
send the credentials if the url is handled by the password manager.
Note: please use realm=None when calling add_password.'''
def http_request(self, req):
url = req.get_full_url()
realm = None
# this is very similar to the code from retry_http_basic_auth()
# but returns a request object.
user, pw = self.passwd.find_user_password(realm, url)
if pw:
raw = "%s:%s" % (user, pw)
auth = 'Basic %s' % base64.b64encode(raw).strip()
req.add_unredirected_header(self.auth_header, auth)
return req
https_request = http_request
그런 다음 나처럼 게으르다면 핸들러를 전역 적으로 설치하십시오.
api_url = "http://api.foursquare.com/"
api_username = "johndoe"
api_password = "some-cryptic-value"
auth_handler = PreemptiveBasicAuthHandler()
auth_handler.add_password(
realm=None, # default realm.
uri=api_url,
user=api_username,
passwd=api_password)
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
답변
MailChimp의 API에 액세스하는 동안 발생한 유사한 문제를 처리하기 위해 사용하는 방법은 다음과 같습니다. 이것은 더 좋은 형식으로 같은 일을합니다.
import urllib2
import base64
chimpConfig = {
"headers" : {
"Content-Type": "application/json",
"Authorization": "Basic " + base64.encodestring("hayden:MYSECRETAPIKEY").replace('\n', '')
},
"url": 'https://us12.api.mailchimp.com/3.0/'}
#perform authentication
datas = None
request = urllib2.Request(chimpConfig["url"], datas, chimpConfig["headers"])
result = urllib2.urlopen(request)
답변
두 번째 매개 변수는 도메인 이름이 아닌 URI 여야합니다. 즉
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, "http://api.foursquare.com/", username, password)