OneDrive API Python ขอโพสต์เพื่ออัปโหลดไฟล์ทำให้เกิดข้อผิดพลาด 401

ฉันกำลังพยายามใช้ OneDrive API, ADAL และ Python request.post เพื่ออัปโหลดไฟล์ไปยังโฟลเดอร์ Sharepoint แต่ได้รับข้อผิดพลาด 401

การอนุญาต ADAL ทำงานเมื่อได้รับการตอบสนองโทเค็นที่ถูกต้องและสร้าง access_token ที่ใช้งานได้

ฉันสามารถใช้ access_token เพื่อดาวน์โหลดไฟล์จากโฟลเดอร์ Sharepoint เดียวกันได้

แม้ว่าจะใช้งานได้เฉพาะเมื่อฉันคัดลอก print file_url url ที่สร้างด้วยโค้ดลงในเบราว์เซอร์ด้วยตนเอง อย่างไรก็ตาม urllib.urlretrieve(file_url, local_file_name) สร้างเฉพาะไฟล์ชื่อ myfilename.csv ที่มีเนื้อหา 403 Forbidden

การอนุญาตของฉันใช้ชื่อผู้ใช้และรหัสผ่านแบบฮาร์ดโค้ด และฉันกำลังบันทึกโทเค็นการรีเฟรชเป็นข้อความที่ชัดเจน และจะดึงข้อมูลทุกครั้งเมื่อดึงข้อมูลการตอบสนองของโทเค็น:

import adal
import urllib
import requests

## set variables
username = '[email protected]'
password = 'mypassword'
authorization_url = 'https://login.windows.net/mydomain.onmicrosoft.com' # Authority
redirect_uri = 'https://login.microsoftonline.com/login.srf'
client_id = 'xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx' # Client id

## use ADAL to create token response
token_response = adal.acquire_token_with_username_password(
        authorization_url,
        username,
        password
    )

## create refresh token and save it to use later 
refresh_token = token_response['refreshToken']
refresh_token_file = open('refresh_token.txt', 'w')
refresh_token_file.write(refresh_token)
refresh_token_file.close()

## get saved refresh token and use it to get new token response
refresh_token = open('refresh_token.txt', 'r').read()
token_response = adal.acquire_token_with_refresh_token(authorization_url, str(refresh_token))

## get access_token from token response
access_token = token_response.get('accessToken') 

การตอบสนองของโทเค็นนั้นถูกต้อง และการใช้โทเค็นการเข้าถึงจากนั้นโค้ดต่อไปนี้จะสร้าง file_url url ที่ฉันสามารถคัดลอกและวางลงในเบราว์เซอร์ด้วยตนเองที่ดาวน์โหลดไฟล์ได้สำเร็จ อย่างไรก็ตาม urllib.urlretrieve(file_url, local_file_name) สร้างเฉพาะไฟล์ชื่อ myfilename.csv ที่มีเนื้อหา 403 Forbidden:

## download file
file_url = 'https://mydomain.sharepoint.com/Shared%20Documents/myfoldername/myfilename.csv?token_response=' + str(access_token)
local_file_name = 'myfilename.csv'
urllib.urlretrieve(file_url, local_file_name)

อย่างไรก็ตาม ฉันยังไม่สามารถอัปโหลดไปยังโฟลเดอร์ Sharepoint นี้ได้สำเร็จ ขณะนี้ฉันมีดังต่อไปนี้:

# upload file
site_url = 'https://mydomain.sharepoint.com/'
headers = {'Authorization':'BEARER ' + str(access_token)}
r = requests.post(site_url, files={'Shared%20Documents/myfoldername/myfilename.csv': open('myfilename.csv', 'rb')}, headers=headers)

print r.text

ซึ่งก่อให้เกิดการตอบสนอง

401 UNAUTHORIZED 

แอป Azure AD ของฉันมีสิทธิ์:

Read and write all user files 
Read and write items and lists in all site collections
(not sure both are needed to upload files)

คำขอของฉันโพสต์ดูโอเคไหม ค่อนข้างแน่ใจว่าฉันกำลังส่งส่วนหัว โฟลเดอร์ และไฟล์อย่างถูกต้อง

แก้ไขเพื่อเพิ่ม:

เมื่อพิจารณาจากข้อเท็จจริงที่ว่าทั้งโค้ดดาวน์โหลดส่งคืน 403 Forbidden และโค้ดอัปโหลดส่งคืน 401 Unauthorized ฉันสงสัยว่าปัญหาอยู่ที่วิธีที่ urllib และ requests ส่ง URL

แก้ไขเพื่อเพิ่ม:

กำลังพยายามสร้าง URL ของไฟล์เพื่อใช้ใน GET และ PUT หลังจากที่ฉันได้รับการรับรองความถูกต้องแล้ว ฉันสามารถป้อน URL นี้ลงในเบราว์เซอร์ได้ด้วยตนเอง:

https://mydomain.sharepoint.com/_api/v1.0/files/root

ซึ่งส่งคืน XML ต่อไปนี้:

{"@odata.context":"https://mydomain.sharepoint.com/_api/v1.0/$metadata#files/$entity"
,"@odata.type":"#Microsoft.FileServices.Folder"
,"@odata.id":"https://mydomain.sharepoint.com/_api/v1.0/files/01QEW7725BZO3N6Y2GOV54373IPWSELRRZ"
,"@odata.editLink":"files/01QEW7725BZO3N6Y2GOV54373IPWSELRRZ"
,"createdBy":null
,"eTag":null
,"id":"01QEW7725BZO3N6Y2GOV54373IPWSELRRZ"
,"lastModifiedBy":null
,"name":"/"
,"parentReference":null
,"size":0
,"dateTimeCreated":"2013-07-31T02:35:57Z"
,"dateTimeLastModified":"2016-05-23T03:55:46Z"
,"type":"Folder"
,"webUrl":"https://mydomain.sharepoint.com/Shared%20Documents"
,"childCount":1}

อย่างไรก็ตาม ยังไม่พบไวยากรณ์ที่ถูกต้องสำหรับการอ้างอิงไปยังไฟล์ ตัวอย่างเช่น สิ่งนี้ใช้งานไม่ได้:

https://mydomain.sharepoint.com/_api/v1.0/files/root:/myfoldername/myfilename.csv:/content

นี่เป็นข้อผิดพลาดที่ส่งคืน:

    {"error":"invalid_client","error_description":"Invalid audience Uri 'https:\/\/m
anagement.core.windows.net\/'."}

ฉันคิดว่าการได้รับการอ้างอิงเฉพาะไปยังไฟล์คือสิ่งที่ฉันต้องทำเพื่อให้มันใช้งานได้


person curtisp    schedule 23.05.2016    source แหล่งที่มา
comment
คุณแน่ใจหรือว่าดาวน์โหลดไฟล์ของคุณถูกต้อง? ฉันลองใช้โค้ดของคุณแล้ว แทนที่จะดาวน์โหลดไฟล์ กลับให้ไฟล์ html ซึ่งเปลี่ยนเส้นทางฉันไปที่อื่น   -  person Jack Zeng    schedule 24.05.2016
comment
ให้ตายเถอะ คุณพูดถูก มันดาวน์โหลดไม่ถูกต้อง มันสร้างไฟล์ชื่อ myfilename.csv แต่เนื้อหามีเพียง 403 Forbidden เมื่อฉันพิมพ์ file_url และคัดลอก URL ผลลัพธ์ลงในเบราว์เซอร์โดยตรง มันจะดาวน์โหลดไฟล์ได้อย่างถูกต้อง ฉันจะอัปเดตคำถาม   -  person curtisp    schedule 24.05.2016


คำตอบ (1)


มีหลายสิ่งที่ต้องแก้ไขที่นี่

ก่อนอื่น คุณต้องส่งต่อรหัสลูกค้าและทรัพยากรไปยัง Acquis_token_with_username_password ของคุณ สิ่งนี้จะช่วยให้คุณสามารถเข้าถึงกราฟ (ซึ่งคุณสามารถเข้าถึง OneDrive) ไม่เช่นนั้นคุณเพียงแค่ได้รับสิทธิ์ในการลงชื่อเข้าใช้ในโทเค็นนั้น

resource_url = "https://graph.microsoft.com";

token_response = ada.acquire_token_with_username_password(
    authorization_url,
    username,
    password,
    client_id
    resource_url
)

หากคุณได้รับข้อผิดพลาดแจ้งว่าจำเป็นต้องมี client_secret o client_assertion คุณต้องลงทะเบียนแอป Azure ใหม่และเลือก Native Client หากคุณได้รับข้อผิดพลาดแจ้งว่าคุณต้องการข้อความโต้ตอบ คุณจะต้องยินยอมให้แอปด้วยตนเองเป็นครั้งแรกในเบราว์เซอร์โดยไปที่

https://login.microsoftonline.com/mydomain.com/oauth2/authorize?client_id=client_id&resource=resource_url&response_type=code+id_token&nonce=1234

ตรวจสอบให้แน่ใจว่าคุณแทนที่ mydomain.com, client_id และ resources_url

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

หากต้องการดาวน์โหลดไฟล์ ไม่แน่ใจว่าคุณได้วิธีการ "?token_response=x" มาจากไหน แต่ฉันไม่คิดว่าวิธีนี้จะได้ผล (ใช้งานไม่ได้เมื่อฉันทดสอบ) คุณต้องใช้ URL อื่นและส่งโทเค็นผู้ถือเช่นเดียวกับที่คุณทำตามคำขอโพสต์ของคุณ

site_url = 'https://graph.microsoft.com/v1.0/drive/root:/myfoldername/myfilename.csv:/content'
headers = {'Authorization':'BEARER ' + str(access_token)}
r = requests.get(site_url, headers=headers)
print r.text

ข้อมูลเพิ่มเติมเกี่ยวกับการรับไฟล์ที่นี่: https://dev.onedrive.com/items/download.htm

สำหรับการอัพโหลด คุณจะต้องเปลี่ยน URL ของคุณด้วย เป็นค่าเดียวกับตัวพิมพ์ GET และเปลี่ยนจาก POST เป็น PUT ด้วย

site_url = 'https://graph.microsoft.com/v1.0/drive/root:/myfoldername/myfilename.csv:/content'
headers = {'Authorization':'BEARER ' + str(access_token)}
r = requests.put(site_url, data = open('myfilename.csv', 'rb')}, headers=headers)
print r.text

ข้อมูลเพิ่มเติมเกี่ยวกับการอัปโหลดไฟล์ที่นี่: https://dev.onedrive.com/items/upload_put.htm

person Saca    schedule 25.05.2016
comment
โอเค ฉันเข้าใจแล้ว ฉันเพิ่งตรวจสอบสิทธิ์ผู้ใช้ด้วย Azure AD ไม่ใช่แอป แต่ adal.acquire_token_with_username_password ตั้งค่าทั้งสองอย่าง client_id และ resource ถึง None - person curtisp; 26.05.2016
comment
ฉันสามารถอนุมัติการปิด login.microsoftonline.com ได้ จำเป็นต้องแก้ไข ADAL's class _DefaultValues ในไฟล์ __init__.py ซึ่งมีค่าเริ่มต้นสำหรับ client_id และ resource เพื่อให้ตรงกับค่าเหล่านั้นสำหรับแอปของฉัน เช่น client_id = client_id ของแอป Azure AD ของฉัน และ resource = https://tenant.sharepoint.com/เพื่อแก้ไขปัญหาผู้ชมที่ไม่ถูกต้อง แก้ไข file_url เป็น 'tenant.sharepoint ด้วย .com/_api/v2.0/drive/root:/myfoldername/' - person curtisp; 26.05.2016