【问题标题】:403 Authorization_RequestDenied when trying to read users403 Authorization_RequestDenied 尝试读取用户时
【发布时间】:2019-11-15 13:49:21
【问题描述】:

我正在尝试使用 API 端点 https://graph.microsoft.com/v1.0/users/ 获取 Exchange 目录中所有用户的列表 这使用 Graph Explorer 有效,我得到一个包含 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代码,大部分是从python-sample-console-app复制过来的

CLIENT_ID = '765bdd8d-b33d-489b-a039-3cdf41223aa4'

AUTHORITY_URL = 'https://login.microsoftonline.com/common'
RESOURCE = 'https://graph.microsoft.com'
API_VERSION = 'v1.0'

import base64
import mimetypes
import os
import urllib
import webbrowser

from adal import AuthenticationContext
import pyperclip
import requests

def device_flow_session(client_id, auto=False):
    """Obtain an access token from Azure AD (via device flow) and create
    a Requests session instance ready to make authenticated calls to
    Microsoft Graph.
    client_id = Application ID for registered "Azure AD only" V1-endpoint app
    auto      = whether to copy device code to clipboard and auto-launch browser
    Returns Requests session object if user signed in successfully. The session
    includes the access token in an Authorization header.
    User identity must be an organizational account (ADAL does not support MSAs).
    """
    ctx = AuthenticationContext(AUTHORITY_URL, api_version=None)
    device_code = ctx.acquire_user_code(RESOURCE, client_id)

    # display user instructions
    if auto:
        pyperclip.copy(device_code['user_code']) # copy user code to clipboard
        webbrowser.open(device_code['verification_url']) # open browser
        print(f'The code {device_code["user_code"]} has been copied to your clipboard, '
              f'and your web browser is opening {device_code["verification_url"]}. '
              'Paste the code to sign in.')
    else:
        print(device_code['message'])

    token_response = ctx.acquire_token_with_device_code(RESOURCE,
                                                        device_code,
                                                        client_id)
    if not token_response.get('accessToken', None):
        return None

    session = requests.Session()
    session.headers.update({'Authorization': f'Bearer {token_response["accessToken"]}',
                            'SdkVersion': 'sample-python-adal',
                            'x-client-SKU': 'sample-python-adal'})
    return session

def api_endpoint(url):
    """Convert a relative path such as /me/photo/$value to a full URI based
    on the current RESOURCE and API_VERSION settings in config.py.
    """
    if urllib.parse.urlparse(url).scheme in ['http', 'https']:
        return url # url is already complete
    return urllib.parse.urljoin(f'{RESOURCE}/{API_VERSION}/',
url.lstrip('/'))

session = device_flow_session(CLIENT_ID, True)
users = session.get(api_endpoint('users'))
print(users.json())

我还在 Microsoft Azure 门户中设置了以下权限:

具体来说,User.ReadBasic.All 应该足以获取所有用户的列表,只包含姓名和电子邮件等基本属性,但它仍然不起作用。

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

解决方案 1

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

解决方案 2

  • 检测到“Authorization_RequestDenied”错误
  • 如果发生这种情况,请打开带有特殊登录 URL 的浏览器窗口以征求用户同意
  • 请用户在登录成功并同意后重启应用
  • 这里是相关代码
CONSENT_URL = f'https://login.microsoftonline.com/common/oauth2/authorize?client_id={CLIENT_ID}&response_type=code&response_mode=query&resource=https://graph.microsoft.com&state=12345&prompt=consent'
#...
response = session.get(api_endpoint('users')).json()
if 'error' in response and response['error']['code'] == 'Authorization_RequestDenied':
    print("Access denied. Consent page has been opened in the webbrowser. Please give user consent, then start the script again!")
    webbrowser.open(CONSENT_URL)
    sys.exit(1)

【问题讨论】:

  • 感谢您使用解决方案更新您的问题。我尝试在 azure 门户上创建一个新应用程序并开始工作。

标签: python azure-active-directory microsoft-graph-api adal permission-denied


【解决方案1】:

当您第一次使用图表浏览器时,您必须征得您的同意才能使用该浏览器。

因此,当您使用在 azure 门户中注册的应用程序登录时,您还必须被要求同意使用该应用程序。但是,如果您在同意后添加/更新权限。您必须再次同意。

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

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-26
  • 2020-05-13
  • 2013-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多