【发布时间】:2019-12-24 21:52:05
【问题描述】:
我最终尝试使用 Graph API 将数据添加到我的 OneDrive 中的 Excel 文件,并在我的 PC 上运行本地 node.js 应用程序,而不是网站,我的目标是简单地调用“node index.js”控制台来执行此操作,而无需授权我的登录(也许这是不可能的?)
我从这些端点开始首先获取简单数据,但无法让它们工作(基本 URL https://graph.microsoft.com):
/v1.0/me//v1.0/users/{My-UserID}//v1.0/me/drive/root:/TestFile.xlsx:/workbook/worksheets/v1.0/users/{My-UserID}/drive/root:/TestFile.xlsx:/workbook/worksheets
/v1.0/me/ 和 /v1.0/users/{My-UserID}/ 返回 'Resource \'{My-UserID}\' 不存在或其查询的引用属性对象之一不存在。'
/v1.0/me/drive/root:/TestFile.xlsx:/workbook/worksheets 和 /v1.0/users/{My-UserID}/drive/root:/TestFile.xlsx:/workbook/worksheets 返回“租户没有 SPO 许可证。”。
我是如何获得令牌的
我使用 adal-node 库 (https://www.npmjs.com/package/adal-node) 获得了访问令牌,使用“通过客户端凭据的服务器到服务器”流程。
我如何调用图形 API
我在没有 Microsoft Graph SDK 的情况下使用 axios 手动调用 API。
我如何在 Azure 门户中注册我的应用
- 我去了“Azure Active Directory”。
- 点击“应用注册”。
- 点击“新注册”。
-
a) 选择一个应用名称。
b) 在“支持的帐户类型”中选择“仅限此组织目录中的帐户(仅限默认目录 - 单个租户)”。
c) 将“重定向 URI(可选)”留空
- 点击“注册”。
- 复制了“应用程序(客户端)ID”并将其用作下面我的应用程序中的“客户端ID”常量。
- 复制了“目录(租户)ID”并将其用作下面我的应用中的“租户”常量。
- 点击“证书和机密”。
- 点击“新客户端密码”。
-
a) 将“描述”留空。
b) 在“过期”下选择“从不”。
c) 点击“添加”。
- 复制生成的密钥并将其用作下面我的应用程序中的“ClientSecret”常量。
- 点击了“API 权限”。
- 点击“添加权限”。
- 单击“Microsoft Graph”。
- 单击“应用程序权限”。
- 已选中“Files.Read.All”。
- 点击“添加权限”。
- 点击“为默认目录授予管理员许可”,点击“是”。
我还尝试添加委托权限,检查“Directory.Read.All”和“Group.Read.All”的所有可用权限和应用程序权限。
我的尝试
我已经尝试使用 Graph Explorer (https://developer.microsoft.com/en-us/graph/graph-explorer) 并且可以看到两者 /v1.0/me/ 和 /v1.0/me/drive/root:/TestFile.xlsx:/workbook/worksheets 返回正确的数据。
我也尝试将 /me/ 替换为 /users/{My-UserID}/ 并且 Graph Explorer 返回相同的正确数据,但我的 node.js 应用程序仍然返回相同的错误。
我使用 JWT 解码器来检查我检索到的令牌,看起来像
oid正确等于 {My-UserID}。roles包括“Files.Read.All”和“User.Read.All”,这是我在 Azure 门户中的应用注册中设置的。appid正确地等于 {My-ApplicationID}。tid正确地等于 {My-TenantID}。aud等于'https://graph.microsoft.com'
我还尝试通过使用标头调用 POST 到 https://login.microsoftonline.com/{My-TenantID}/oauth2/v2.0/token 手动获取令牌:
'Content-Type': 'application/x-www-form-urlencoded'
和数据:
client_id=${My-ClientID}&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret={My-ClientSecret}&grant_type=client_credentials
并收到此错误:“AADSTS7000215:提供了无效的客户端密码”。 编辑:我发现了为什么会出现这个错误。我必须使用 %{ascii-code-in-hex} 转义特殊字符,例如:/+。
其他注意事项
我有一个 Office 365 家庭订阅和一个使用与我的 OneDrive 相同的电子邮件地址的即用即付 Azure 帐户,其中包含我想要添加数据的 Excel 文件。
编辑:我发现如果您使用 Graph Explorer 并致电 /v1.0/users/{any-number},您将获得您自己的个人资料。这意味着{My-UserID} 可能一直不是我的正确用户 ID。
const Tenant = {My-TenantID};
const ClientID = {My-ApplicationID};
const ClientSecret = {My-ClientSecret};
function GetAccessToken()
{
const AuthenticationContext = require('adal-node').AuthenticationContext;
const authorityUrl = `https://login.microsoftonline.com/${Tenant}`;
const applicationId = ClientID;
const clientSecret = ClientSecret;
const resource = 'https://graph.microsoft.com';
const context = new AuthenticationContext(authorityUrl);
return new Promise((resolve, reject) =>
{
context.acquireTokenWithClientCredentials(resource, applicationId, clientSecret, (error, tokenResponse) =>
{
if (error)
{
console.log('Get token error:');
console.dir(error.stack, {depth: null});
reject(error);
}
else
{
console.log('Get token success:');
console.dir(tokenResponse, {depth: null});
resolve(tokenResponse.accessToken);
}
});
});
}
async function GetData()
{
const axios = require('axios');
const AccessToken = await GetAccessToken();
axios(
{
method: 'GET',
url: 'https://graph.microsoft.com/v1.0/me/', //I have also tried /v1.0/users/{My-UserID}/
headers:
{
'Authorization': `Bearer ${AccessToken}`,
}
})
.then(result =>
{
console.log('Get data success:');
console.dir(result.data, {depth: null});
})
.catch(error =>
{
console.log('Get data failed:');
if (error.response.data != undefined)
{
console.dir(error.response.data, {depth: null});
}
else
{
console.dir(error, {depth: null});
}
})
}
GetData();
更新 1
我想我已经弄清楚为什么 /v1.0/me 和 /v1.0/users/{My-UserID} 都不起作用了。如果我们在没有用户的情况下进行身份验证(我在此处选择的流程),则应用程序能够访问的唯一用户是 Azure Active Directory (AAD) 中的用户。现在,如果您使用 hotmail 帐户登录 Azure 并转到“Azure Active Directory”然后“用户”,您将在那里看到您的帐户,但我认为该帐户实际上与您的“普通”Microsoft 帐户不同(“common ' Microsoft 帐户是您使用 hotmail 注册的帐户)。是的,Microsoft 似乎创建了一个单独的“AAD”身份,这是一个不同于您的“普通”身份用户的用户。
{My-UserID} 实际上是“普通”身份的用户 ID。所以..这意味着如果我调用/v1.0/users/{My-UserID},我的应用程序将无法识别该用户 ID,因为该用户 ID 不属于 AAD。所以我尝试的是从 AAD 中的用户那里复制“对象 ID”,然后改用它:/v1.0/users/{AAD-ObjectID} 然后中提琴,我看到了我的个人资料。
编辑:{My-UserID} 实际上不是我的“普通”身份的用户 ID。这是我还不知道的其他 ID。
然后我尝试了:
- 创建一个新应用程序,但不要在“支持的帐户类型”中选择“仅此组织目录中的帐户(仅默认目录 - 单租户)”,而是选择“任何组织目录中的帐户(任何 Azure AD 目录 - 多租户)”,然后个人 Microsoft 帐户(例如 Skype、Xbox)”
- 遵循“代表用户获取访问权限”身份验证流程
并且可以确认通过此流程,/v1.0/me 和 v1.0/users/{My-UserID} 确实有效。 编辑:无论您指定什么 ID,Graph API 实际上都会返回我的个人资料,因此您可以指定v1.0/users/123,它仍然会返回您的个人资料!
所以我想,嗯,与其从 Azure 门户授予管理员许可,不如使用 https://login.microsoftonline.com/common/adminconsent 端点授予管理员许可。这样做,然后从/common/oauth2/v2.0/token 获取访问令牌
-
/v1.0/me返回“当前经过身份验证的上下文对此请求无效。” -
/v1.0/users/{My-UserID}返回“无法建立调用应用程序的身份”错误。 -
/v1.0/users/{AAD-ObjectID}返回“无法建立调用应用程序的身份”错误。
如果我从/{My-TenantID}/oauth2/v2.0/token 获得访问令牌,那么
-
/v1.0/me和/v1.0/users/{My-UserID}返回原始的“Request_ResourceNotFound”错误。 -
/v1.0/users/{AAD-ObjectID}正确返回了我的个人资料。
然后我尝试了/v1.0/users/{AAD-ObjectID}/drive/root:/TestFile.xlsx:/workbook/worksheets,但仍然收到“租户没有 SPO 许可证”。我怀疑这是因为我的 AAD 身份没有必要的许可证来操作 OneDrive 项目。
在不关闭“代表用户获取访问权限”身份验证流程的情况下将数据添加到 Excel 的解决方法是使用 Logic App 代替。因此,在逻辑应用程序中,我设置了一个 HTTP 请求端点,触发该端点时会将数据添加到 Excel 并让我的 Node.js 应用程序调用此端点,而不是直接调用 Graph API。
总结
我认为这可能是 Microsoft 必须最终解决的问题 - AAD 身份不应该是单独的身份,而是与我的“通用”身份相同的身份,以便我可以使用 /v1.0/users/{My-UserID} 访问我的用户信息并使用 /v1.0/users/{My-UserID}/drive 操作我的 OneDrive 文件。
更新 2
我找到了一种不使用逻辑应用直接调用 Graph API 的方法!
所以对于那些关注我的问题的人来说,有两种方式调用 Graph API:
- 代表用户致电
- 在没有用户的情况下调用
我想出的关键点是“代表用户调用”就像是说,你,用户,想通过你的应用程序使用 Graph API,这实际上是我想要的,因为我想调用 Graph API 来编辑我的 Excel 文件。 “在没有用户的情况下调用”就像是说,应用程序本身正在调用 Graph API - 而不是使用应用程序调用 Graph API 的用户,因此它无法访问用户数据,除非该用户在活动目录中。重要的是要注意(根据我之前的回答),您在 AAD 中看到的与您同名的用户实际上并不是“您”,而是您的“AAD”版本。因此,即使您在 AAD 中看到您的姓名,“无用户呼叫”也将无法访问您的 OneDrive 项目。为此,您需要“代表用户致电”。
现在,如果我们需要“代表用户调用”,我想我每次都必须通过“获取授权码 --> 获取访问令牌”来访问我的 OneDrive 文件,但我刚刚发现您还可以刷新令牌,这样您就可以继续访问 OneDrive 文件,而无需获取新的授权码。这一步最重要的是确保在获取授权码和获取token时在scope参数中包含offline_access,否则在请求token时不会返回refreshToken,你将无法刷新令牌。您还需要在您的应用注册中添加offline_access 委派权限。
因此,我可以让我的节点应用程序保存 refreshToken 并在每次运行时刷新令牌,并且中提琴,我可以随时编辑我的 Excel 文件!
【问题讨论】:
标签: node.js microsoft-graph-api