[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)


답변

나는 현재 솔루션 내 패키지 사용하는 것을 제안 urllib2_prior_auth 에이 꽤 잘 (I 사업 해결 을 포함 표준 lib 디렉토리에 있습니다.


답변