คำขอ Python: คำขอ POST วางส่วนหัวการอนุญาต


9

ฉันพยายามสร้างคำขอ API POST โดยใช้ไลบรารีคำขอ Python ฉันกำลังผ่านAuthorizationส่วนหัว แต่เมื่อฉันลองดีบั๊กฉันจะเห็นว่าส่วนหัวนั้นกำลังลดลง ฉันไม่รู้ว่าเกิดอะไรขึ้น

นี่คือรหัสของฉัน:

access_token = get_access_token()
bearer_token = base64.b64encode(bytes("'Bearer {}'".format(access_token)), 'utf-8')
headers = {'Content-Type': 'application/json', 'Authorization': bearer_token}
data = '{"FirstName" : "Jane", "LastName" : "Smith"}'
response = requests.post('https://myserver.com/endpoint', headers=headers, data=data)

ที่คุณสามารถดูข้างต้นผมการตั้งAuthorizationหัวในการขัดแย้งคำขอ {'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.4.3 CPython/2.7.9 Linux/4.1.19-v7+'}แต่มันจะหายไปส่วนหัวคำขอจริง:

ข้อมูลเพิ่มเติมคือถ้าฉันเปลี่ยนคำขอ POST เป็นการร้องขอ GET Authorizationส่วนหัวจะผ่านตามปกติ!

เหตุใดห้องสมุดนี้จึงวางส่วนหัวสำหรับคำขอ POST และฉันจะทำให้ส่วนนี้ทำงานได้อย่างไร

การใช้ v2.4.3 ของคำร้องขอ lib และ Python 2.7.9

คำตอบ:


10

TLDR

URL ที่คุณร้องขอเปลี่ยนเส้นทางคำขอ POST ไปยังโฮสต์อื่นดังนั้นไลบรารีคำขอลดลงAuthoriztionส่วนหัวเพราะกลัวว่าจะรั่วไหลข้อมูลประจำตัวของคุณ เพื่อแก้ไขว่าคุณสามารถแทนที่วิธีที่รับผิดชอบในSessionชั้นเรียนของคำขอ

รายละเอียด

ในคำขอ 2.4.3 สถานที่เดียวที่reqeuestsจะลบAuthorizationส่วนหัวคือเมื่อคำขอถูกเปลี่ยนเส้นทางไปยังโฮสต์อื่น นี่คือรหัสที่เกี่ยวข้อง :

if 'Authorization' in headers:
    # If we get redirected to a new host, we should strip out any
    # authentication headers.
    original_parsed = urlparse(response.request.url)
    redirect_parsed = urlparse(url)

    if (original_parsed.hostname != redirect_parsed.hostname):
        del headers['Authorization']

ในรุ่นใหม่ของrequestsที่Authorizationส่วนหัวจะลดลงในกรณีเพิ่มเติม (เช่นถ้าเปลี่ยนเส้นทางจากการรักษาความปลอดภัยให้โปรโตคอลที่ไม่ปลอดภัย)

ดังนั้นสิ่งที่อาจเกิดขึ้นในกรณีของคุณคือคำขอ POST ของคุณจะถูกเปลี่ยนเส้นทางไปยังโฮสต์อื่น วิธีเดียวที่คุณสามารถให้การรับรองความถูกต้องสำหรับโฮสต์ที่ถูกเปลี่ยนเส้นทางโดยใช้ไลบรารีคำขอคือผ่าน.netrcไฟล์ น่าเศร้าที่จะให้คุณใช้การรับรองความถูกต้องพื้นฐานของ HTTP เท่านั้นซึ่งไม่ได้ช่วยอะไรคุณมากนัก ในกรณีนั้นทางออกที่ดีที่สุดน่าจะเป็น subclass requests.Sessionและแทนที่พฤติกรรมนี้เช่น:

from requests import Session

class NoRebuildAuthSession(Session):
    def rebuild_auth(self, prepared_request, response):
        """
        No code here means requests will always preserve the Authorization
        header when redirected.
        Be careful not to leak your credentials to untrusted hosts!
        """

session = NoRebuildAuthSession()
response = session.post('https://myserver.com/endpoint', headers=headers, data=data)

แก้ไข

ฉันได้เปิดคำขอดึงไปยังไลบรารีคำขอใน Github เพื่อเพิ่มคำเตือนเมื่อเกิดเหตุการณ์นี้ รอการอนุมัติครั้งที่สองที่จะรวมเข้าด้วยกัน (สามเดือนแล้ว)


1
ขอบคุณนี่เป็นปัญหา!
user4184113

0

นี่คือสิ่งที่เอกสารการขอพูดว่า:

Authorization headers set with headers= will be overridden if credentials are specified in .netrc, which in turn will be overridden by the auth= parameter. Authorization headers will be removed if you get redirected off-host.

คุณได้รับการเปลี่ยนเส้นทางในคำขอของคุณหรือไม่

หากเป็นกรณีนี้ให้ลองปิดการใช้งานการเปลี่ยนเส้นทางด้วยตัวเลือกนี้ในคำขอโพสต์:

allow_redirects=False


allow_redirects=Falseจะป้องกันไม่ให้คำขอติดตามการเปลี่ยนเส้นทางที่ร้องขอโดยเซิร์ฟเวอร์ นี่จะไม่ช่วยทำตามคำขอมันจะหยุดตรงกลาง
kmaork

0

ปัญหาแรก (และอาจเกิดขึ้นจริง) ที่ฉันเห็นคือวิธีที่คุณสร้างbearer_tokenเพราะคุณไม่ได้เข้ารหัสโทเค็นของคุณเท่านั้น แต่ยังเป็นประเภทการตรวจสอบความถูกต้อง'Bearer'

ตามที่ฉันเข้าใจคุณต้องเข้ารหัสโทเค็นและต้องระบุประเภทการรับรองความถูกต้องว่างเปล่า + โทเค็นที่เข้ารหัสภายในส่วนหัวคำขอของคุณ:

bearer_token = str(base64.b64encode(access_token.encode()), "utf8")
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(bearer_token)}

หากเป็นปัญหาการเปลี่ยนเส้นทางคุณสามารถค้นหาตำแหน่งที่ถูกต้องและส่งคำขอไปยัง url นี้หรือคุณอาจคิดถึงการส่งโทเค็นการเข้าถึงภายในเนื้อหาของคุณPOSTหากเซิร์ฟเวอร์ยอมรับสิ่งนี้


0

จากเอกสาร: Requests will attempt to get the authentication credentials for the URL’s hostname from the user’s netrc file. The netrc file overrides raw HTTP authentication headers set with headers=. If credentials for the hostname are found, the request is sent with HTTP Basic Auth.

หากคุณถูกเปลี่ยนเส้นทางคุณสามารถลองใช้งานได้ allow_redirects=false


-1

คุณสามารถลองใช้การอนุญาตที่กำหนดเองได้ในส่วนหัว

กำหนดคลาสการพิสูจน์ตัวตนแบบกำหนดเอง:

class MyAuth(requests.auth.AuthBase):
def __init__(self, bearer_token):
    self.username = None
    self.bearer_token = bearer_token

def __call__(self, r):
    r.headers['Authorization'] = self.bearer_token
    return r

จากนั้นใช้สิ่งนี้เพื่อส่งคำขอ:

headers = {'Content-Type': 'application/json'}

data = '{"FirstName" : "Jane", "LastName" : "Smith"}'

response = requests.post('https://myserver.com/endpoint', headers=headers, auth=MyAuth(bearer_token), data=data)

หากได้ผลโปรดยอมรับคำตอบ หรือหากคุณยังมีปัญหาโปรดแจ้งให้เราทราบ หวังว่านี่จะช่วยได้


requests.auth.AuthBaseไม่มีความจำเป็นต้องรับมรดกจากเป็น ถ้าคุณดูซอร์สโค้ดของมันคุณจะเห็นว่าทั้งหมดมันไม่เพิ่มขึ้นหากคุณลืมที่จะแทนที่NotImplemented __call__
Reinstate Monica

สิ่งนี้จะไม่เปลี่ยนพฤติกรรมที่อธิบายไว้ในคำถาม เมื่อสร้างการรับรองความถูกต้องใหม่ในการเปลี่ยนเส้นทางคำขอจะไม่ใช้อาร์กิวเมนต์การรับรองความถูกต้อง
kmaork
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.