尝试通过 Flask 应用程序访问
"https://graph.microsoft.com/v1.0/me/drive"
端点会产生以下响应:
{
"error": {
"code": "HostNotFound",
"innerError": {
"client-request-id": "{xxx}",
"date": "2024-04-02T15:47:03",
"request-id": "{yyy}"
},
"message": "Target '{zzz}-my.sharepoint.com' is not found."
}
print(token["scope"])
# openid profile email https://graph.microsoft.com/Application.Read.All https://graph.microsoft.com/Files.Read https://graph.microsoft.com/Files.Read.All https://graph.microsoft.com/Files.ReadWrite.All https://graph.microsoft.com/Sites.Read.All https://graph.microsoft.com/Sites.ReadWrite.All https://graph.microsoft.com/User.Export.All https://graph.microsoft.com/User.Read https://graph.microsoft.com/.default
"https://graph.microsoft.com/v1.0/applications"
或 "https://graph.microsoft.com/v1.0/me"
因此,我认为代币生成不是问题。由于我仍然试图首先获得工作访问权限,因此令牌当前通过会话传递,装饰器在附加授权标头后执行最终请求。这不是我打算长期使用/实施的。 我很高兴收到任何建议/行业标准,以及如何正确处理和纳入这一点。然而,这个问题的焦点主要是为什么我无法通过 Microsoft Graph API 访问我的个人 OneDrive 文件。
app.py
import json
from functools import wraps
import msal
import requests
from flask import Flask, session, request, redirect, make_response, url_for
app = Flask(__name__)
with open("delegated_config.json") as file:
config = json.load(file)
app.config.update(config)
client_instance = msal.ConfidentialClientApplication(
client_id=app.config["application_id"],
client_credential=app.config["client_secret"],
authority=app.config["authority_url"]
)
def initiate_auth_flow():
"""Authentication with Access Token"""
if not session.get("auth_flow"):
authorization = client_instance.initiate_auth_code_flow(
app.config["scope"], redirect_uri=app.config["redirect_uri"]
)
session["auth_flow"] = authorization
authorization = session.get("auth_flow")
# Will redirect to "generate_token()"
return make_response(redirect(authorization["auth_uri"]))
def get_token(func):
@wraps(func)
def wrapper(*args, **kwargs):
if not session.get("access_token"):
session["execute_func"] = func.__name__
return initiate_auth_flow()
else:
url = func(*args, **kwargs)
return requests.get(
url, headers={"Authorization": f"Bearer {session['access_token']}"}).json()
return wrapper
# Redirect route after logging in and confirming permissions
@app.route("/generate_token")
def generate_token():
query_string = request.args
token = client_instance.acquire_token_by_auth_code_flow(session["auth_flow"],
auth_response=query_string)
session["access_token"] = token["access_token"]
return redirect(url_for(session["execute_func"]))
# WORKS
@app.route("/me")
@get_token
def me():
return "https://graph.microsoft.com/v1.0/me"
# WORKS
@app.route("/all_applications")
@get_token
def all_applications():
return "https://graph.microsoft.com/v1.0/applications"
# DOES NOT WORK, ERROR AT BEGINNING OF QUESTION
@app.route("/all_drives")
@get_token
def all_drives():
return "https://graph.microsoft.com/v1.0/me/drive"
# DOES NOT WORK
@app.route("/private_drive")
@get_token
def private_drive():
return "https://api.onedrive.com/v1.0/me/drive"
# {"error": {"code": "invalidRequest", "message": "Invalid API or resource"}}
delegate_config.json
{
"SECRET_KEY": "{xxx}",
"application_id": "{yyy}",
"client_secret": "{zzz}",
"authority_url": "https://login.microsoftonline.com/{tenant_id}",
"scope": [ "https://graph.microsoft.com/.default" ],
"redirect_uri": "http://localhost:6123/generate_token"
}
最终我自己弄清楚了。我所要做的就是不将我的租户的特定authority_url传递给
ConfidentialClientApplication
,所以即
client_instance = msal.ConfidentialClientApplication(
client_id=app.config["application_id"],
client_credential=app.config["client_secret"]
)
...这将导致使用默认的
authority_url
,即 https://login.microsoftonline.com/common
。
事后想想,也有道理。初始错误代码表明 Microsoft Graph 无法在租户中为我的用户找到 OneDrive/Sharepoint。然而,由于我想访问我的个人 OneDrive 的数据(该数据不包含在我的组织中),因此在使用应用程序对自己进行身份验证后,我只需使用
/common
端点即可访问它。