【问题标题】:Azure AD: "scope" Property Missing from Access Token Response BodyAzure AD:访问令牌响应正文中缺少“范围”属性
【发布时间】:2017-05-13 04:33:46
【问题描述】:

我正在编写一个 Python 脚本来编辑 SharePoint 中的 Excel 电子表格。我们有 Office 365 商业版。我正在使用 Microsoft Graph API。 我在 Microsoft Azure Active Directory (AD) 中注册了 Python 应用程序,并为 Graph API 添加了以下 2 个(仅限应用程序)权限:(1) 在所有网站集中读取和写入文件(预览版)和 (2) 读取目录数据。 (我让我们的公司管理员为我注册了该应用程序。)

我的 Python 脚本使用 requests 库发送 REST 请求:

import json
import requests

MSGRAPH_URI = 'https://graph.microsoft.com'
VERSION = 'v1.0'

def requestAccessToken(tenant_id, app_id, app_key):
    MSLOGIN_URI = 'https://login.microsoftonline.com'
    ACCESS_TOKEN_PATH = 'oauth2/token'
    GRANT_TYPE = 'client_credentials'
    endpoint = '{0}/{1}/{2}'.format(MSLOGIN_URI, tenant_id, ACCESS_TOKEN_PATH)
    headers = {'Content-Type': 'Application/Json'}
    data = {
        'grant_type': GRANT_TYPE,
        'client_id': app_id,
        'client_secret': app_key,
        'resource': MSGRAPH_URI

    }
    access_token = response.json()['access_token']
    return access_token

def getWorkbookID(access_token, fileName):
    endpoint = '{0}/{1}/me/drive/root/children'.format(MSGRAPH_URI, VERSION)
    headers = {
        'Content-Type': 'Application/Json',
        'Authorization': 'Bearer {}'.format(access_token)
    }
    response = requests.get(endpoint, headers=headers)
    print response.text
    assert response.status_code == 200
    items = response.json()['value']
    workbook_id = None
    for item in items:
        if item['name'] == fileName:
            workbook_id = item['id']
    return workbook_id

access_token = requestAccessToken(TENANT_ID, APP_ID, APP_KEY)
workbook_id = getWorkbookID(access_token, WORKBOOK_FILENAME)

Python 应用成功地从 Microsoft 服务器请求并接收到 access_token。访问令牌是这样开始的

eyJ0eXAiOiJKV1QiLCJub25jZSI6...

然后它在 getWorkbookID() 中请求我的文件列表:

GET https://graph.microsoft.com/v1.0/me/drive/root/children
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6...

这是对该 REST 请求的响应:

{
  "error": {
    "code": "InternalServerError",
    "message": "Object reference not set to an instance of an object.",
    "innerError": {
      "request-id": "aa97a822-7ac5-4986-8ac0-9852146e149a",
      "date": "2016-12-26T22:13:54"
    }
  }
}

请注意,当我通过 Graph Explorer (https://graph.microsoft.io/en-us/graph-explorer) 请求文件时,我成功获取了文件列表。

编辑:

  1. 将标题从“Microsoft Graph API 返回未设置为对象实例的对象引用”更改为“访问令牌响应中缺少 Azure AD“范围”。
  2. 在阅读以下内容后,将 GET 请求的 uri 中的“me”更改为“myOrganization”:graph.microsft.io/en-us/docs/overview/call_api

也就是说,

GET https://graph.microsoft.com/v1.0/myOrganization/drive/root/children
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6...

现在得到以下响应。

{
  "error": {
    "code": "AccessDenied",
    "message": "Either scp or roles claim need to be present in the token.",
    "innerError": {
      "request-id": "bddb8c51-535f-456b-b43e-5cfdf32bd8a5",
      "date": "2016-12-28T22:39:25"
    }
  }
}

查看 graph.microsoft.io/en-us/docs/authorization/app_authorization 中的示例,我看到访问令牌响应正文包含一个“范围”属性,该属性列出了在应用注册期间授予应用的权限.但是,我从服务器收到的访问令牌响应没有“范围”属性。这是我的访问令牌响应的样子。

{
"token_type":"Bearer",
"expires_in":"3599",
"ext_expires_in":"0",
"expires_on":"1482968367",
"not_before":"1482964467",
"resource":"https://graph.microsoft.com",
"access_token":"eyJ0eXAiOiJKV..."
}

问题:

  1. 我让管理员在 Azure AD 中注册了应用程序,并选中了所需的 Microsoft Graph API 应用程序权限复选框。显然这还不够。还需要什么?为什么访问令牌响应正文中没有权限?
  2. GET 请求的正确 URI 是什么? “MyOrganization”是 URI 中的正确值吗?

【问题讨论】:

  • 该错误是 .NET 中的经典 NullReferenceException。可能是 API 中的错误,或者缺少预期的东西。似乎不是权限问题。

标签: python azure office365 microsoft-graph-api


【解决方案1】:

感谢大家的回复。经过更多研究,我找到了问题的答案。

原来的问题:“Microsoft Graph API Returns Object reference not set to an instance of an object”

请求

GET https://graph.microsoft.com/v1.0/me/drive/root/children
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6...

得到响应

{
  "error": {
    "code": "InternalServerError",
    "message": "Object reference not set to an instance of an object.",
    "innerError": {
      "request-id": "aa97a822-7ac5-4986-8ac0-9852146e149a",
      "date": "2016-12-26T22:13:54"
    }
  }
}

正如@SriramDhanasekaran-MSFT 所述,/me 指的是当前登录的用户。在我们的例子中,我们没有登录用户,所以我们不能使用/me。相反,我们可以使用/myOrganization 或不使用,这是可选的。

更新后的问题:“访问令牌响应中缺少 Azure AD“范围”属性”

更新的(将 /me 替换为 /myOrganization)请求

GET https://graph.microsoft.com/v1.0/myOrganization/drive/root/children
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6...

得到响应

{
  "error": {
    "code": "AccessDenied",
    "message": "Either scp or roles claim need to be present in the token.",
    "innerError": {
      "request-id": "bddb8c51-535f-456b-b43e-5cfdf32bd8a5",
      "date": "2016-12-28T22:39:25"
    }
  }
}

正如@SriramDhanasekaran-MSFT 和@DanKershaw-MSFT 所述,access_token 响应缺少scope 属性的原因是管理员未在 Azure AD 中“授予”权限。

但是,@SriramDhanasekaran-MSFT 提供的解决方案:

https://login.microsoftonline.com/common/oauth2/authorize?client_id=&response_type=code&redirect_uri=http://localhost&resource=https://graph.microsoft.com&prompt=consent

对我没有帮助,因为我的应用没有 redirect uri。授予权限的解决方案比这更简单:只需让管理员登录 Azure AD,然后单击“授予权限”链接即可授予权限。

此外,/myOrganization/driver/root/children 列出了管理员驱动器的内容。正如@PeterPan-MSFT 所说,要列出不同用户的驱动器,请将/myOrganization 替换为/users/<user-id>

成功:

我的应用程序现在可以在线编辑我的 Excel 电子表格,无需人工干预。与@PeterPan-MSFT 所说的相反,这可以通过 Graph API 实现,无需下载 Excel 电子表格并离线编辑。

总结:

有两个问题:(1)使用/me和(2)管理员没有在Azure AD中授予应用程序权限。

【讨论】:

    【解决方案2】:

    由于正在使用 client_credential 令牌流(即,没有经过身份验证的用户上下文),任何带有 /me 的请求都无效,因为 /me 指的是当前登录用户。如果您要访问用户驱动器中的文件,请尝试使用委托令牌。

    要访问 Sharepoint 中的根驱动器,请求 url 是 /drive/root/children(myorganization 是可选的)。

    关于丢失的声明,管理员必须同意该应用程序。您可以通过要求管理员访问以下网址来强制同意(替换为您应用的网址)

    https://login.microsoftonline.com/common/oauth2/authorize?client_id=&response_type=code&redirect_uri=http://localhost&resource=https://graph.microsoft.com&prompt=consent

    【讨论】:

    • 只是为了补充斯里拉姆的答案。一旦您按照指示获得管理员同意(可能需要将 redirect_uri 与您为应用注册的内容相匹配),您现在将在访问令牌中看到一个 roles 声明,它指示角色(或应用程序权限)授予应用程序(使用 client_credential 流时)。注意:如果您使用的是委托(代码)流,您会在访问令牌中找到 scp 声明。
    【解决方案3】:

    正如@juunas所说,下面的第一个错误信息应该是.NET中的NULL异常,它是在服务器端引起的,但也不是API错误或权限问题。

    error": {
        "code": "InternalServerError",
        "message": "Object reference not set to an instance of an object.",
    

    您可以参考SO thread了解此案例,后台似乎正在更新,请稍后再试。

    为了解释第二个错误,当您将 Graph API url 中的选项 me 更改为 myOrganization 时,如 @SriramDhanasekaran-MSFT,它正在使用 <user-id> 而不是访问当前用户或指定用户的文件me.

    但是,根据我的理解,您想为您的组织编辑位于 SharePoint 中的 Excel 电子表格,这似乎不适合使用 Graph API。根据我的经验,应该通过使用 OneDrive for Business 的 API 将 Excel 文件复制到本地进行编辑和上传以覆盖它,请参考the dev documents for OneDrive 并尝试使用the API for drive resource

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-15
      • 2021-04-18
      • 2018-02-07
      • 2023-02-10
      • 2020-02-10
      • 1970-01-01
      • 2019-09-22
      • 2020-09-09
      相关资源
      最近更新 更多