Python 403尝试读取用户时,授权请求被拒绝

Python 403尝试读取用户时,授权请求被拒绝,python,azure-active-directory,microsoft-graph-api,adal,permission-denied,Python,Azure Active Directory,Microsoft Graph Api,Adal,Permission Denied,我正在尝试使用API端点获取Exchange目录中所有用户的列表 这项工作使用,我得到了一个预览列表的100个有效结果 但是,当从我的Python应用程序访问同一个端点,并使用同一用户登录时,我得到以下响应: {'error': {'code': 'Authorization_RequestDenied', 'message': 'Insufficient privileges to complete the operation.', 'innerError': {'request-id': '

我正在尝试使用API端点获取Exchange目录中所有用户的列表 这项工作使用,我得到了一个预览列表的100个有效结果

但是,当从我的Python应用程序访问同一个端点,并使用同一用户登录时,我得到以下响应:

{'error': {'code': 'Authorization_RequestDenied', 'message': 'Insufficient privileges to complete the operation.', 'innerError': {'request-id': '6924dba1-83ee-4865-9dcf-76b6cafcb808', 'date': '2019-07-04T21:08:28'}}}
这是我正在使用的Python代码,其中大部分是从

CLIENT_ID='765bdd8d-b33d-489b-a039-3cdf41223aa4'
当局https://login.microsoftonline.com/common'
资源管理https://graph.microsoft.com'
API_版本='v1.0'
导入base64
导入模拟类型
导入操作系统
导入URL库
导入网络浏览器
从adal导入AuthenticationContext
进口pyperclip
导入请求
def设备流量会话(客户端id,auto=False):
“”“从Azure AD获取访问令牌(通过设备流)并创建
请求会话实例已准备好对进行身份验证调用
微软图形。
client_id=已注册的“Azure AD only”V1端点应用程序的应用程序id
自动=是否将设备代码复制到剪贴板并自动启动浏览器
如果用户成功登录,则返回Requests会话对象
在授权标头中包含访问令牌。
用户标识必须是组织帐户(ADAL不支持MSAs)。
"""
ctx=AuthenticationContext(权限\ URL,api\版本=无)
设备代码=ctx.acquire用户代码(资源、客户端id)
#显示用户说明
如果自动:
pyperclip.copy(设备_代码['user_代码])#将用户代码复制到剪贴板
webbrowser.open(设备代码['verification_url'])#打开浏览器
打印(代码{device_code[“user_code”]}已复制到剪贴板,'
f'并且您的web浏览器正在打开{device_code[“verification_url”]}。'
“粘贴要登录的代码。”)
其他:
打印(设备代码['message'])
令牌\u响应=ctx。使用\u设备\u代码获取\u令牌\u(资源,
设备代码,
客户(身份证)
如果不是token\u response.get('accessToken',None):
一无所获
会话=请求。会话()
update({'Authorization':f'Bearer{token_response[“accessToken”]}),
'SdkVersion':'sample python adal',
'x-client-SKU':'sample python adal'})
返回会话
def api_端点(url):
“”“将相对路径(如/me/photo/$value)转换为基于URI的完整路径。”
在config.py中的当前资源和API_版本设置上。
"""
如果['http','https']中的urllib.parse.urlparse(url.scheme):
返回url#url已完成
返回urllib.parse.urljoin(f'{RESOURCE}/{API_VERSION}/',
url.lstrip('/'))
会话=设备流会话(客户端ID,True)
users=session.get(api_端点('users'))
打印(users.json())
我还在Microsoft Azure门户中设置了以下权限:

具体地说,
User.ReadBasic.All
应该足以获得一个所有用户的列表,其中只包含名称和电子邮件等基本属性,但它仍然不起作用

显然,这个问题缺少“用户同意”。这里有些奇怪,因为理论上,登录页面应该自动请求用户同意所有配置的API权限。经过进一步的修补,我找到了以下解决方案:

解决方案1

  • 在portal.azure.com上注册新应用程序
  • 预先添加所需的配置和API权限
  • 更改所需的API权限时,不会再次询问用户
  • 随时需要在portal.azure.com上重新创建应用程序,以访问新的API并相应地更改应用程序中的应用程序ID
解决方案2

  • 检测到“授权请求被拒绝”错误
  • 如果发生这种情况,请打开带有特殊登录URL的浏览器窗口,以征求用户同意
  • 请用户在成功登录并获得同意后重新启动应用程序
  • 这是相关代码
同意\u URL=f'https://login.microsoftonline.com/common/oauth2/authorize?client_id={CLIENT\u ID}&response\u type=code&response\u mode=query&resource=https://graph.microsoft.com&state=12345&prompt=consent'
#...
response=session.get(api_端点('users')).json()
如果响应中的“错误”和响应['error']['code']==='Authorization\u RequestDenied':
打印(“访问被拒绝。同意页已在webbrowser中打开。请给予用户同意,然后再次启动脚本!”)
webbrowser.open(同意\u URL)
系统出口(1)

首次使用图形资源管理器时,必须获得使用该资源管理器的许可

因此,当您使用在azure portal中注册的应用程序登录时,您还必须获得使用该应用程序的许可。但如果您在同意后添加/更新权限。你必须再次同意

您可以通过url请求强制用户同意,将&prompt=同意附加到身份验证请求url

或者您只是代表此目录中的所有用户授予同意。为所有用户授予管理员许可意味着最终用户在使用应用程序时不会显示许可屏幕


首次使用图形资源管理器时,必须征得您的同意才能使用该资源管理器

因此,当您使用在azure portal中注册的应用程序登录时,您还必须获得使用该应用程序的许可。但如果您在同意后添加/更新权限。你必须再次同意

您可以通过url请求强制用户同意,将&prompt=同意附加到身份验证请求url

或者您只是代表此目录中的所有用户授予同意。授予al的管理员许可