Microsoft Graph API 使用 Python 阅读邮件
Microsoft Graph API Read Mail with Python
我正在尝试创建一个 python 脚本,它可以持续从我组织中的服务帐户读取邮件。我正在尝试使用 Microsoft Graph API,但我读得越多,就越感到困惑。我已经在 Azure 门户中注册了一个应用程序并拥有我的客户端 ID、客户端密码等,据我所知,您必须使用这些,调用 API 需要您将 url 粘贴到浏览器中登录同意访问,并提供仅持续一个小时的令牌?我如何以编程方式执行此操作?
我想我的问题是,有没有人有幸用图表 api 做到这一点?我怎样才能做到这一点而不必每小时进行一次浏览器握手?我希望能够 运行 这个脚本并让它 运行 而不用担心需要经常刷新令牌。我只是愚蠢,还是这种方式太复杂了哈哈。非常感谢任何关于人们如何对图 api 进行身份验证并保持身份验证的 python 示例!
我今天只是在做类似的事情。 (Microsoft 最近弃用了用于交换的基本身份验证,我无法再使用简单的 username/password 从我支持的 Web 应用程序发送邮件。)
使用 Microsoft msal python 库 https://github.com/AzureAD/microsoft-authentication-library-for-python
和 sample/device_flow_sample.py 中的示例,我能够构建一个 user-based 登录来检索访问令牌并刷新令牌以保持登录状态(使用“设备流身份验证”)。 msal 库处理令牌缓存的存储和重新加载,以及在必要时刷新令牌。
下面是第一次登录的代码
#see https://github.com/AzureAD/microsoft-authentication-library-for-python/blob/dev/sample/device_flow_sample.py
import sys
import json
import logging
import os
import atexit
import requests
import msal
# logging
logging.basicConfig(level=logging.DEBUG) # Enable DEBUG log for entire script
logging.getLogger("msal").setLevel(logging.INFO) # Optionally disable MSAL DEBUG logs
# config
config = dict(
authority = "https://login.microsoftonline.com/common",
client_id = 'YOUR CLIENT ID',
scope = ["User.Read"],
username = 'user@domain',
cache_file = 'token.cache',
endpoint = 'https://graph.microsoft.com/v1.0/me'
)
# cache
cache = msal.SerializableTokenCache()
if os.path.exists(config["cache_file"]):
cache.deserialize(open(config["cache_file"], "r").read())
atexit.register(lambda:
open(config["cache_file"], "w").write(cache.serialize())
if cache.has_state_changed else None)
# app
app = msal.PublicClientApplication(
config["client_id"], authority=config["authority"],
token_cache=cache)
# exists?
result = None
accounts = app.get_accounts()
if accounts:
logging.info("found accounts in the app")
for a in accounts:
print(a)
if a["username"] == config["username"]:
result = app.acquire_token_silent(config["scope"], account=a)
break
else:
logging.info("no accounts in the app")
# initiate
if result:
logging.info("found a token in the cache")
else:
logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
flow = app.initiate_device_flow(scopes=config["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() # Some terminal needs this to ensure the message is shown
# Ideally you should wait here, in order to save some unnecessary polling
input("Press Enter after signing in from another device to proceed, CTRL+C to abort.")
result = app.acquire_token_by_device_flow(flow) # By default it will block
# You can follow this instruction to shorten the block time
# https://msal-python.readthedocs.io/en/latest/#msal.PublicClientApplication.acquire_token_by_device_flow
# or you may even turn off the blocking behavior,
# and then keep calling acquire_token_by_device_flow(flow) in your own customized loop.
if result and "access_token" in result:
# Calling graph using the access token
graph_data = requests.get( # Use token to call downstream service
config["endpoint"],
headers={'Authorization': 'Bearer ' + result['access_token']},).json()
print("Graph API call result: %s" % json.dumps(graph_data, indent=2))
else:
print(result.get("error"))
print(result.get("error_description"))
print(result.get("correlation_id")) # You may need this when reporting a bug
您需要修复配置,并更新相应权限的范围。
所有的魔法都在这里:
result = app.acquire_token_silent(config["scope"], account=a)
并将授权 access_token 放入请求中 headers:
graph_data = requests.get( # Use token to call downstream service
config["endpoint"],
headers={'Authorization': 'Bearer ' + result['access_token']},).json()
只要您在调用任何图形 API 之前调用 acquire_token_silent
,令牌就会保持最新状态。刷新令牌有效期为 90 天左右,并且会自动更新。登录后,令牌将被更新并存储在缓存中(并持久保存到文件中),并将无限期地保持活动状态more-or-less(有些东西可以在服务器端使其无效)。
不幸的是,我仍然遇到问题,因为它是一个未经验证的 multi-tenant 应用程序。我成功地将用户添加为我的租户中的来宾,并且登录有效,但是一旦我尝试在范围内获得更多有趣的特权,用户就无法登录 - 我要么必须验证我的 mpn,或者让我客户的第 3 方 IT 人员管理员在他们的租户中授予此应用程序的权限。如果我拥有他们租户的管理员权限,我可能会查看守护程序身份验证方法而不是 user-based。
(要清楚,上面的代码几乎是逐字逐句的 msal 示例,带有配置和持久性调整)
我正在尝试创建一个 python 脚本,它可以持续从我组织中的服务帐户读取邮件。我正在尝试使用 Microsoft Graph API,但我读得越多,就越感到困惑。我已经在 Azure 门户中注册了一个应用程序并拥有我的客户端 ID、客户端密码等,据我所知,您必须使用这些,调用 API 需要您将 url 粘贴到浏览器中登录同意访问,并提供仅持续一个小时的令牌?我如何以编程方式执行此操作?
我想我的问题是,有没有人有幸用图表 api 做到这一点?我怎样才能做到这一点而不必每小时进行一次浏览器握手?我希望能够 运行 这个脚本并让它 运行 而不用担心需要经常刷新令牌。我只是愚蠢,还是这种方式太复杂了哈哈。非常感谢任何关于人们如何对图 api 进行身份验证并保持身份验证的 python 示例!
我今天只是在做类似的事情。 (Microsoft 最近弃用了用于交换的基本身份验证,我无法再使用简单的 username/password 从我支持的 Web 应用程序发送邮件。)
使用 Microsoft msal python 库 https://github.com/AzureAD/microsoft-authentication-library-for-python
和 sample/device_flow_sample.py 中的示例,我能够构建一个 user-based 登录来检索访问令牌并刷新令牌以保持登录状态(使用“设备流身份验证”)。 msal 库处理令牌缓存的存储和重新加载,以及在必要时刷新令牌。
下面是第一次登录的代码
#see https://github.com/AzureAD/microsoft-authentication-library-for-python/blob/dev/sample/device_flow_sample.py
import sys
import json
import logging
import os
import atexit
import requests
import msal
# logging
logging.basicConfig(level=logging.DEBUG) # Enable DEBUG log for entire script
logging.getLogger("msal").setLevel(logging.INFO) # Optionally disable MSAL DEBUG logs
# config
config = dict(
authority = "https://login.microsoftonline.com/common",
client_id = 'YOUR CLIENT ID',
scope = ["User.Read"],
username = 'user@domain',
cache_file = 'token.cache',
endpoint = 'https://graph.microsoft.com/v1.0/me'
)
# cache
cache = msal.SerializableTokenCache()
if os.path.exists(config["cache_file"]):
cache.deserialize(open(config["cache_file"], "r").read())
atexit.register(lambda:
open(config["cache_file"], "w").write(cache.serialize())
if cache.has_state_changed else None)
# app
app = msal.PublicClientApplication(
config["client_id"], authority=config["authority"],
token_cache=cache)
# exists?
result = None
accounts = app.get_accounts()
if accounts:
logging.info("found accounts in the app")
for a in accounts:
print(a)
if a["username"] == config["username"]:
result = app.acquire_token_silent(config["scope"], account=a)
break
else:
logging.info("no accounts in the app")
# initiate
if result:
logging.info("found a token in the cache")
else:
logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
flow = app.initiate_device_flow(scopes=config["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() # Some terminal needs this to ensure the message is shown
# Ideally you should wait here, in order to save some unnecessary polling
input("Press Enter after signing in from another device to proceed, CTRL+C to abort.")
result = app.acquire_token_by_device_flow(flow) # By default it will block
# You can follow this instruction to shorten the block time
# https://msal-python.readthedocs.io/en/latest/#msal.PublicClientApplication.acquire_token_by_device_flow
# or you may even turn off the blocking behavior,
# and then keep calling acquire_token_by_device_flow(flow) in your own customized loop.
if result and "access_token" in result:
# Calling graph using the access token
graph_data = requests.get( # Use token to call downstream service
config["endpoint"],
headers={'Authorization': 'Bearer ' + result['access_token']},).json()
print("Graph API call result: %s" % json.dumps(graph_data, indent=2))
else:
print(result.get("error"))
print(result.get("error_description"))
print(result.get("correlation_id")) # You may need this when reporting a bug
您需要修复配置,并更新相应权限的范围。
所有的魔法都在这里:
result = app.acquire_token_silent(config["scope"], account=a)
并将授权 access_token 放入请求中 headers:
graph_data = requests.get( # Use token to call downstream service
config["endpoint"],
headers={'Authorization': 'Bearer ' + result['access_token']},).json()
只要您在调用任何图形 API 之前调用 acquire_token_silent
,令牌就会保持最新状态。刷新令牌有效期为 90 天左右,并且会自动更新。登录后,令牌将被更新并存储在缓存中(并持久保存到文件中),并将无限期地保持活动状态more-or-less(有些东西可以在服务器端使其无效)。
不幸的是,我仍然遇到问题,因为它是一个未经验证的 multi-tenant 应用程序。我成功地将用户添加为我的租户中的来宾,并且登录有效,但是一旦我尝试在范围内获得更多有趣的特权,用户就无法登录 - 我要么必须验证我的 mpn,或者让我客户的第 3 方 IT 人员管理员在他们的租户中授予此应用程序的权限。如果我拥有他们租户的管理员权限,我可能会查看守护程序身份验证方法而不是 user-based。
(要清楚,上面的代码几乎是逐字逐句的 msal 示例,带有配置和持久性调整)