使用Python调用SharePoint Rest API遇403权限错误的解决咨询
问题
我尝试通过Python的office365库访问SharePoint文件夹并获取文件,代码如下:
# Import libraries from office365.sharepoint.client_context import ClientContext from office365.runtime.auth.client_credential import ClientCredential # Config for Sharepoint (to be stored in env later) SP_CLIENT_ID = xxx SP_CLIENT_SECRET = xxx SP_URL = 'https://<organization_url>.sharepoint.com/sites/<site-name>' relative_folder_url = '/Shared%20Documents/<subfolder>' # App-based authentication with access credentials context = ClientContext(SP_URL).with_credentials(ClientCredential(SP_CLIENT_ID, SP_CLIENT_SECRET)) folder = context.web.get_folder_by_server_relative_url(relative_folder_url) context.load(folder) context.execute_query() # Processes each Sharepoint file in folder for file in folder.files: print(f'Processing file: {file.properties["Name"]}')
运行时抛出403权限错误:
office365.runtime.client_request_exception.ClientRequestException: ('-2147024891, System.UnauthorizedAccessException', 'Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))', "403 Client Error: Forbidden for url: https://<tenant-name>.sharepoint.com/sites/<site-id>/_api/Web/getFileByServerRelativePath(DecodedUrl='%2Fsites%2F<site-name>%2FDocuments%2FGeneral%2F<subfolder>')")
该错误来自context.execute_query()。
我用相同的SP_CLIENT_ID和SP_CLIENT_SECRET在Postman中通过Graph API可以正常获取文件:先生成令牌,再在GET请求中传入令牌即可,说明应用本身的认证没问题。
现在需要解决这个403问题,让Python代码能通过SharePoint REST API查看并下载文件;同时纠结是继续用office365库,还是改用requests这类纯API方式。
解决方案
一、修复office365库的权限问题
核心问题是Azure应用未被授予SharePoint REST API的权限(该权限与Graph API权限相互独立),需按以下步骤配置:
- 登录Azure门户,找到对应的应用注册
- 进入「API权限」页面,点击「添加权限」
- 选择「SharePoint」->「应用权限」
- 添加所需权限:
- 仅查看文件选
Sites.Read.All,需下载/修改选Sites.ReadWrite.All - 若仅需访问特定站点,可添加
Sites.Selected(需额外绑定站点权限)
- 仅查看文件选
- 点击「授予管理员同意」(需全局管理员操作)
同时修正代码中的路径格式:relative_folder_url无需URL编码,直接使用原始路径即可,库会自动处理编码,修改后代码片段:
relative_folder_url = '/Shared Documents/<subfolder>'
二、改用requests调用Graph API实现文件操作
既然Postman中Graph API已验证可用,直接用requests调用是更快捷的方案,步骤如下:
1. 获取访问令牌
import requests # 配置参数 tenant_id = "<your-tenant-id>" client_id = "<your-client-id>" client_secret = "<your-client-secret>" site_name = "<your-site-name>" folder_path = "/Shared Documents/<subfolder>" # 获取令牌 token_url = f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token" token_payload = { "grant_type": "client_credentials", "client_id": client_id, "client_secret": client_secret, "scope": "https://graph.microsoft.com/.default" } token_response = requests.post(token_url, data=token_payload) access_token = token_response.json()["access_token"]
2. 获取文件夹中的文件列表
# 获取站点ID site_response = requests.get( f"https://graph.microsoft.com/v1.0/sites/{tenant_id}:/sites/{site_name}", headers={"Authorization": f"Bearer {access_token}"} ) site_id = site_response.json()["id"] # 获取文件夹下的文件 folder_response = requests.get( f"https://graph.microsoft.com/v1.0/sites/{site_id}/drive/root:/{folder_path}:/children", headers={"Authorization": f"Bearer {access_token}"} ) files = folder_response.json()["value"] for file in files: print(f"Processing file: {file['name']}")
3. 下载文件
# 下载单个文件示例 file_id = "<file-id-from-previous-step>" download_response = requests.get( f"https://graph.microsoft.com/v1.0/sites/{site_id}/drive/items/{file_id}/content", headers={"Authorization": f"Bearer {access_token}"}, stream=True ) with open(file["name"], "wb") as f: for chunk in download_response.iter_content(chunk_size=8192): f.write(chunk)
方案选择建议
- 若需复杂SharePoint操作(如文档库管理、版本控制等),建议修复
office365库的权限问题,该库封装了更多SharePoint特有功能 - 若仅需文件列表获取和下载,用
requests调用Graph API更轻量,且认证流程已验证可用
内容的提问来源于stack exchange,提问作者ooalgomaniac
相关产品推荐
相关产品推荐

