如何通过ClientCredentialFlow授权MS Project ODATA API?权限与范围咨询
解决MS Project ODATA API的ClientCredentialFlow认证问题
一、Azure应用注册的权限配置
你需要在Azure应用注册中添加SharePoint的应用权限(不是委托权限),具体操作和可选权限如下:
- 进入Azure应用注册→API权限→添加权限→选择「SharePoint」→选择「应用权限」
- 根据需求选择以下权限之一或多个:
ProjectWebAppReporting.Read.All:只读访问Project Web App报告数据Project.Read.All:读取所有项目数据Project.Write.All:读写所有项目数据ProjectWebApp.FullControl.All:完全控制Project Web App
- 添加权限后必须点击授予管理员同意(仅租户管理员可操作),否则Client Credential Flow无法获取到有效权限的token
二、Scope设置
使用Client Credential Flow时,scope固定为以下格式:
scopes = ["https://<你的租户域名>.sharepoint.com/.default"]
.default会自动包含你已配置并授权的所有应用权限,无需指定单个权限名称。
三、API请求错误的修正
你能拿到token但API返回“请求无效或格式错误”,主要是两个问题:
- API端点不正确:
/_api/ProjectData/不是有效的ODATA资源,需要指定具体的数据集,比如项目列表:
其他可用数据集如ms_project_api_url = 'https://<你的租户域名>.sharepoint.com/sites/your_project_instance/_api/ProjectData/Projects'Tasks、Resources等,可按需调整。 - 缺失请求头:添加
Accept: application/json确保服务返回JSON格式响应:headers = { 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json', 'Accept': 'application/json' }
修正后的代码示例
import requests import msal def get_access_token(): tenant_id = "你的租户ID" client_id = "你的客户端ID" client_secret = "你的客户端密钥" confidential_client = msal.ConfidentialClientApplication( client_id, authority=f"https://login.microsoftonline.com/{tenant_id}", client_credential=client_secret ) scopes = ["https://你的租户域名.sharepoint.com/.default"] result = confidential_client.acquire_token_for_client(scopes=scopes) if "access_token" in result: return result["access_token"] else: print("获取access token失败:", result.get("error_description")) return None def get_project_data(): ms_project_api_url = 'https://你的租户域名.sharepoint.com/sites/your_project_instance/_api/ProjectData/Projects' access_token = get_access_token() if access_token: headers = { 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json', 'Accept': 'application/json' } response = requests.get(ms_project_api_url, headers=headers) if response.status_code == 200: print("数据获取成功:") print(response.json()) else: print(f"请求失败,状态码: {response.status_code}") print("错误详情:", response.text) else: print("无法获取access token") if __name__ == "__main__": get_project_data()
内容的提问来源于stack exchange,提问作者ediordna
相关产品推荐
相关产品推荐

