使用Graph API的SharePoint Access Token读取文件失败,求解决
解决AudienceUriValidationFailedException错误的方案
错误原因
你遇到的Microsoft.IdentityModel.Tokens.AudienceUriValidationFailedException,本质是Access Token的受众(Audience)不匹配:
- 当前获取的Token是针对Microsoft Graph API的(受众为
https://graph.microsoft.com) - 但你用这个Token直接请求SharePoint站点的
webUrl(比如https://xxx.sharepoint.com/...),SharePoint的受众是自身站点域名,因此会拒绝该Token。
解决方案
有两种可行的解决思路:
思路1:改用Microsoft Graph API读取文件内容(推荐)
直接通过Graph API的文件内容端点获取,Token受众完全匹配,无需访问SharePoint原生URL。
修改代码中读取文件的部分:
# 替换原来的requests.get(list["webUrl"], ...)代码 # 从Graph返回的文件对象中提取关键信息,构造内容请求URL file_id = item["id"] # 基于driveId和itemId构造Graph文件内容端点 content_url = f"https://graph.microsoft.com/v1.0/drives/{item['parentReference']['driveId']}/items/{file_id}/content" # 发起请求时要在Authorization头中加上Bearer前缀 response = requests.get(content_url, headers={"Authorization": f"Bearer {token_result['access_token']}"}) # 验证请求结果 if response.status_code == 200: # 保存文件或处理内容 with open(item["name"], "wb") as f: f.write(response.content) print(f"成功读取文件:{item['name']}") else: print(f"读取失败,状态码:{response.status_code},错误信息:{response.text}")
思路2:获取针对SharePoint站点的Access Token
如果必须直接访问SharePoint原生REST API,需要重新获取受众为SharePoint站点的Token:
- 将
scope修改为"https://{你的SharePoint站点域名}/.default"(例如https://contoso.sharepoint.com/.default) - 调用
acquire_token_for_client获取新Token后,用该Token请求SharePoint REST API的文件内容端点(格式为{webUrl}/$value,而非直接请求webUrl)
代码优化建议
你的代码还有几处需要调整的细节:
try-except块捕获异常后,需重新发起Graph请求,否则后续会使用失败的响应数据response = requests.get(...)部分缩进错误,需放入if ele.lower() in list["name"].lower()的代码块内Authorization头必须包含Bearer前缀,格式应为Bearer {access_token}
调整后的核心循环示例:
while True: try: # 构造正确的Authorization头 headers = {"Authorization": f"Bearer {token_result['access_token']}"} graph_result = requests.get(url=url, headers=headers) graph_result.raise_for_status() except Exception as e: print(f"Graph API请求失败:{str(e)}") token_result = client.acquire_token_for_client(scopes=scope) # 重新发起请求 headers = {"Authorization": f"Bearer {token_result['access_token']}"} graph_result = requests.get(url=url, headers=headers) graph_result.raise_for_status() if 'value' in graph_result.json(): items = graph_result.json()['value'] for item in items: for ele in finalReportNames: if ele.lower() in item["name"].lower(): clientreportcount += 1 # 改用Graph API读取文件内容 file_id = item["id"] content_url = f"https://graph.microsoft.com/v1.0/drives/{item['parentReference']['driveId']}/items/{file_id}/content" content_response = requests.get(content_url, headers=headers) if content_response.ok: print(f"成功读取文件:{item['name']}") # 这里可以添加文件内容处理逻辑 else: print(f"文件读取失败:{content_response.text}") # 处理分页 if '@odata.nextLink' in graph_result.json(): url = graph_result.json()['@odata.nextLink'] graphlinkcount += 1 else: break
内容的提问来源于stack exchange,提问作者WhoamI
相关产品推荐
相关产品推荐

