使用Python MSAL库下载OneDrive个人图片时遭遇401 'unauthenticated'错误
使用Python MSAL库下载OneDrive个人图片时遭遇401 'unauthenticated'错误
根据你的描述,你已经成功获取了有效的access token,并且能正常调用Graph API列出OneDrive中的文件,说明你的权限配置和token获取流程都是没问题的。出现401错误的核心原因,是你直接使用@microsoft.graph.downloadUrl这个链接时,缺少了该链接依赖的会话凭证——这个URL是一个预授权的临时链接,它和你浏览器登录时的会话绑定,而你的Python脚本直接请求它时,没有携带对应的会话Cookie,所以会被判定为未认证。
解决方案:使用Graph API标准端点下载文件
更可靠且符合规范的方式是直接通过Graph API的文件内容端点来下载,利用你已经持有的access token进行授权。具体步骤如下:
- 从文件列表的返回结果中,获取每个文件的
id字段(而不是@microsoft.graph.downloadUrl) - 构造Graph API的下载端点:
https://graph.microsoft.com/v1.0/me/drive/items/{file-id}/content - 使用你请求文件列表时的同一个headers(包含
Authorization: Bearer {access_token})发送GET请求到该端点,即可获取文件二进制内容。
修改后的代码示例
在你现有的脚本基础上,添加下载文件的逻辑:
#!/usr/bin/python3 import requests import json from msal import PublicClientApplication ### config app_id = '6cae2a2a-XXX' authority = 'https://login.microsoftonline.com/consumers' scopes = ["User.Read", "User.Export.All", "Files.ReadWrite.All"] ### start main ### ### create app app = PublicClientApplication(app_id, authority=authority) ### get access token result = app.acquire_token_interactive(scopes) if "access_token" in result: print("Got access_token: " + result["access_token"]) else: print(result.get("error")) print(result.get("error_description")) print(result.get("correlation_id")) # You may need this when reporting a bug exit() ### 设置请求头 headers = { "Authorization": "Bearer " + result["access_token"] } ### 1. 获取文件列表 request_url = 'https://graph.microsoft.com/v1.0/me/drive/root:/Bilder/Eigene Aufnahmen:/children' response = requests.get(request_url, headers=headers) if response.status_code != 200: print(f"获取文件列表失败: {response.status_code} - {response.text}") exit() files = response.json().get('value', []) print(f"共找到 {len(files)} 个文件") ### 2. 遍历下载每个文件 for file in files: file_id = file['id'] file_name = file['name'] file_size = file.get('size', '未知') print(f"\n准备下载: {file_name} (大小: {file_size} bytes)") # 构造下载端点 download_url = f"https://graph.microsoft.com/v1.0/me/drive/items/{file_id}/content" download_response = requests.get(download_url, headers=headers) if download_response.status_code == 200: # 保存文件到本地 with open(file_name, 'wb') as f: f.write(download_response.content) print(f"✅ 成功下载文件: {file_name}") else: print(f"❌ 下载失败,状态码: {download_response.status_code},错误信息: {download_response.text}")
额外说明
- 你的权限配置是正确的:
Files.ReadWrite.All权限已经足够读取和下载个人OneDrive中的所有文件 - 这种方式比直接使用临时downloadUrl更稳定,因为它完全依赖你通过MSAL获取的access token,不需要依赖浏览器会话的Cookie
- 如果需要下载大文件,还可以使用Graph API的分段下载功能(通过
Range请求头),避免一次性加载大文件到内存中
备注:内容来源于stack exchange,提问作者Andare
相关产品推荐
相关产品推荐

