Python调用Microsoft Partner接口生成Token及拉取客户数据报错问题
微软Partner Center API Token异常排查解决方案
核心问题根因汇总
你的代码存在资源端点配置错误、请求头冗余硬编码、Token交换逻辑不符合接口规范三个核心问题,同时需校验Azure AD和Partner Center的权限配置,按以下步骤逐一排查即可解决:
排查修复步骤
- 第一步:修正获取Access Token的请求参数
- 首先修正
resource字段值:Partner Center API的资源标识是https://api.partnercenter.microsoft.com,你原本填的https://api.partner.microsoft.com是错误的,导致生成的Token受众不匹配,调用接口必然返回401 - 删除冗余硬编码的请求头:
Content-Length、Host、Expect三个头不需要手动配置,requests库会根据请求体内容自动生成,硬写固定的Content-Length:194会导致不同长度的请求体被截断,直接引发Token校验失败
修正后的代码如下:
import requests import json tanat_id = "你的租户ID" client_id = "你的应用ID" client_secret = "你的应用密钥" url = f"https://login.microsoftonline.com/{tanat_id}/oauth2/token" headers = { "Accept": "application/json", "return-client-request-id": "true", "Content-Type": "application/x-www-form-urlencoded; charset=utf-8" } data = { 'client_id': client_id, 'resource': 'https://api.partnercenter.microsoft.com', 'client_secret': client_secret, 'grant_type': 'client_credentials', } res = requests.post(url, headers=headers, data=data) # 先判断请求是否成功,避免直接取access_token报错 if res.status_code == 200: access_token = json.loads(res.text)["access_token"] else: print(f"获取Token失败:{res.status_code}, {res.text}") - 首先修正
- 第二步:删除不必要的generatetoken接口调用
你当前使用的是客户端凭证流,生成的Token已经是应用级权限凭证,不需要调用generatetoken接口二次交换。generatetoken接口仅用于用户委托场景的授权码流兑换,你的调用参数完全不符合该接口的要求,所以返回invalid_grant错误属于正常现象,直接删除这部分代码即可。 - 第三步:校验权限配置
代码修正后如果还是返回401,需检查两个权限配置:- Azure AD应用权限:在Azure门户的应用注册页面,给你的应用添加
Partner Center API的应用权限(不要选委托权限),权限项选择Customer.Read.All或者更高的客户管理权限,且必须由全局管理员点击同意按钮完成权限授权 - Partner Center关联:你的Azure AD应用必须关联到Partner Center的服务商账号,且给该应用分配对应的客户管理角色,没有关联的应用即使拿到有效Token也无法访问Partner Center资源
- Azure AD应用权限:在Azure门户的应用注册页面,给你的应用添加
- 第四步:验证Token有效性
拿到Access Token后可以先解析Token内容,确认以下字段:aud字段值必须是https://api.partnercenter.microsoft.comroles字段必须包含你申请的客户相关权限exp字段的过期时间在当前时间之后
确认无误后再调用客户列表接口,修正后的接口调用代码如下:
url = "https://api.partnercenter.microsoft.com/v1/customers?size=40" headers = { "Authorization": f"Bearer {access_token}", "Accept": "application/json", } res = requests.get(url, headers=headers) print(res.status_code) print(res.text)
内容的提问来源于stack exchange,提问作者prashant mavadiya
相关产品推荐
相关产品推荐

