【问题标题】:Microsoft Graph Api Python微软图形 API Python
【发布时间】:2021-06-08 15:12:21
【问题描述】:

我正在尝试在我的 python 脚本上执行 microsoft graph 请求:"https://graph.microsoft.com/v1.0/me""https://graph.microsoft.com/v1.0/me/messages" 等等

在使用此 Web 界面 https://developer.microsoft.com/fr-fr/graph/graph-explorer 测试这些请求时,所有请求都有效

在我的脚本上,只有这个请求有效"https://graph.microsoft.com/v1.0/me",其他请求我得到错误

这是我的脚本:

import msal
import jwt
import json
import sys
import requests
from datetime import datetime
from msal_extensions import *
graphURI = 'https://graph.microsoft.com'
tenantID = 'my tenant id'
authority = 'https://login.microsoftonline.com/' + tenantID
clientID = 'my client id'
scope = ["email Files.ReadWrite.All", "Mail.Read", "Mail.Read.Shared", "Mail.ReadBasic", "Mail.ReadWrite", "Mail.ReadWrite.Shared Mail.Send Mail.Send.Shared MailboxSettings.Read MailboxSettings.ReadWrite openid profile Sites.ReadWrite.All User.Read User.ReadBasic.All"]
username = 'yourAADUsername' # i keep this one like this, i don't know what is my username
result = None
tokenExpiry = None
def msal_persistence(location, fallback_to_plaintext=False):
    if sys.platform.startswith('win'):
        return FilePersistenceWithDataProtection(location)
    if sys.platform.startswith('darwin'):
        return KeychainPersistence(location, "my_service_name", "my_account_name")
        return FilePersistence(location)
def msal_cache_accounts(clientID, authority):
# Accounts
    persistence = msal_persistence("token_cache.bin")
    print("Is this MSAL persistence cache encrypted?", persistence.is_encrypted)
    cache = PersistedTokenCache(persistence)
    app = msal.PublicClientApplication(
    client_id=clientID, authority=authority, token_cache=cache)
    accounts = app.get_accounts()
    print(accounts)
    return accounts
def msal_delegated_refresh(clientID, scope, authority, account):
    persistence = msal_persistence("token_cache.bin")
    cache = PersistedTokenCache(persistence)
    app = msal.PublicClientApplication(
    client_id=clientID, authority=authority, token_cache=cache)
    result = app.acquire_token_silent_with_error(
    scopes=scope, account=account)
    return result
def msal_delegated_refresh_force(clientID, scope, authority, account):
    persistence = msal_persistence("token_cache.bin")
    cache = PersistedTokenCache(persistence)
    app = msal.PublicClientApplication(
    client_id=clientID, authority=authority, token_cache=cache)
    result = app.acquire_token_silent_with_error(
    scopes=scope, account=account, force_refresh=True)
    return result
def msal_delegated_device_flow(clientID, scope, authority):
    print("Initiate Device Code Flow to get an AAD Access Token.")
    print("Open a browser window and paste in the URL below and then enter the Code. CTRL+C to cancel.")
    persistence = msal_persistence("token_cache.bin")
    cache = PersistedTokenCache(persistence)
    app = msal.PublicClientApplication(client_id=clientID, authority=authority, token_cache=cache)
    flow = app.initiate_device_flow(scopes=scope)
    if "user_code" not in flow:
        raise ValueError("Fail to create device flow. Err: %s" % json.dumps(flow, indent=4))
    print(flow["message"])
    sys.stdout.flush()
    result = app.acquire_token_by_device_flow(flow)
    return result
def msal_jwt_expiry(accessToken):
    decodedAccessToken = jwt.decode(accessToken, verify=False)
    accessTokenFormatted = json.dumps(decodedAccessToken, indent=2)
    # Token Expiry
    tokenExpiry = datetime.fromtimestamp(int(decodedAccessToken['exp']))
    print("Token Expires at: " + str(tokenExpiry))
    return tokenExpiry
def msgraph_request(resource, requestHeaders):
    # Request
    results = requests.get(resource, headers=requestHeaders).json()
    return results
accounts = msal_cache_accounts(clientID, authority)
if accounts:
    for account in accounts:
        if account['username'] == username:
            myAccount = account
            print("Found account in MSAL Cache: " + account['username'])
            print("Obtaining a new Access Token using the Refresh Token")
            result = msal_delegated_refresh(clientID, scope, authority, myAccount)
print(result)
if result is None:
    # Get a new Access Token using the Device Code Flow
    result = msal_delegated_device_flow(clientID, scope, authority)
    print(result)
else:
    if result["access_token"]:
        msal_jwt_expiry(result["access_token"])
    else:
        # Get a new Access Token using the Device Code Flow
        result = msal_delegated_device_flow(clientID, scope, authority)
if result["access_token"]:
    msal_jwt_expiry(result["access_token"])
    # Query AAD Users based on voice query using DisplayName
    print(graphURI + "/v1.0/me")

requestHeaders = {'Authorization': 'Bearer ' + result["access_token"],'Content-Type': 'application/json'}
queryResults = msgraph_request(graphURI + "/v1.0/me",requestHeaders)
print(json.dumps(queryResults, indent=2))

所以当我执行这个查询时:queryResults = msgraph_request(graphURI + "/v1.0/me",requestHeaders)

输出是:

{
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
  "businessPhones": [],
  "displayName": "Joe Coral",
  "givenName": "Joe",
  "jobTitle": null,
  "mail": null,
  "mobilePhone": null,
  "officeLocation": null,
  "preferredLanguage": "en",
  "surname": "Coral",
  "userPrincipalName": "joe-coral-hotmail.fr#EXT#@joecoralhotmail.onmicrosoft.com",
  "id": "82a2ef56-dbb7-45a4-bc9c-c533fd2c5908"
}

但是当我使用这个查询时:queryResults = msgraph_request(graphURI + "/v1.0/me/messages",requestHeaders)

输出是:

{
  "error": {
    "code": "ResourceNotFound",
    "message": "Resource could not be discovered.",
    "innerError": {
      "date": "2021-06-08T15:03:31",
      "request-id": "fa8dc282-0c8d-4be4-a195-4488c4f86e23",
      "client-request-id": "fa8dc282-0c8d-4be4-a195-4488c4f86e23"
    }
  }
}

在我的 ADD 申请中,我授予了所有权限:

【问题讨论】:

  • 您的帐户有交换许可证吗?

标签: python azure microsoft-graph-api


【解决方案1】:

根据您对/v1.0/me 请求的结果,我可以看到该用户是个人 Microsoft 帐户,并且已作为访客添加到此 AAD 租户中。

当您使用此用户登录 https://developer.microsoft.com/fr-fr/graph/graph-explorer 时,它实际上会将您的帐户视为个人 Microsoft 帐户,而不是来宾用户。

这是因为 Microsoft Graph Explorer 使用 common 端点进行身份验证。 (详情请看我的pervious answer

但是在您的代码中,我看到您输入了authority = 'https://login.microsoftonline.com/' + tenantID,这意味着它将您的帐户视为此租户中的来宾用户。

在这种情况下,当您拨打 /v1.0/me/messages 时,它会尝试从您在 Exchange Online 中托管的 O365 邮箱中获取邮件。但来宾用户没有 Exchange Online 许可证,也没有托管在 Exchange Online 中。这就是为什么您会收到 ResourceNotFound 错误。

因此,根据您的描述,我认为您正试图以个人 Microsoft 帐户而不是来宾用户的身份为用户获取消息。

请将authority = 'https://login.microsoftonline.com/' + tenantID修改为authority = 'https://login.microsoftonline.com/common'。这应该可以解决问题。

【讨论】:

  • 感谢您的回答,我更改了权限并收到此错误:jwt.exceptions.DecodeError: Not enough segments ValueError: no enough values to unpack (expected 2, got 1)
  • @ibrahim 这是因为个人 Microsoft 帐户的访问令牌不是 jwt 令牌。你不能在上面使用jwt.decode。作为一种解决方法,您可以尝试获取 id 令牌并对其进行解码。
猜你喜欢
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-19
  • 2018-01-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多