【问题标题】:Solved: Got Request_ResourceNotFound and Tenant does not have a SPO license when calling Microsoft Graph API已解决:调用 Microsoft Graph API 时出现 Request_ResourceNotFound 且租户没有 SPO 许可证
【发布时间】: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 门户中注册我的应用

  1. 我去了“Azure Active Directory”。
  2. 点击“应用注册”。
  3. 点击“新注册”。
  4. a) 选择一个应用名称。

    b) 在“支持的帐户类型”中选择“仅限此组织目录中的帐户(仅限默认目录 - 单个租户)”。

    c) 将“重定向 URI(可选)”留空

  5. 点击“注册”。
  6. 复制了“应用程序(客户端)ID”并将其用作下面我的应用程序中的“客户端ID”常量。
  7. 复制了“目录(租户)ID”并将其用作下面我的应用中的“租户”常量。
  8. 点击“证书和机密”。
  9. 点击“新客户端密码”。
  10. a) 将“描述”留空。

    b) 在“过期”下选择“从不”。

    c) 点击“添加”。

  11. 复制生成的密钥并将其用作下面我的应用程序中的“ClientSecret”常量。
  12. 点击了“API 权限”。
  13. 点击“添加权限”。
  14. 单击“Microsoft Graph”。
  15. 单击“应用程序权限”。
  16. 已选中“Files.Read.All”。
  17. 点击“添加权限”。
  18. 点击“为默认目录授予管理员许可”,点击“是”。

我还尝试添加委托权限,检查“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/mev1.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


    【解决方案1】:

    您不能将/me 与客户端凭据一起使用。由于您没有对用户进行身份验证,因此 Graph 无法确定“我”应该映射到哪个用户。

    当使用 App-Only 令牌(即客户端凭据)时,您需要指定您想要寻址的用户:

    • /v1.0/users/{id or userPrincipalName}
    • /v1.0/{id or userPrincipalName}/drive/root:/TestFile.xlsx:/workbook/worksheets

    【讨论】:

    • 感谢马克的回复!我尝试用/users/{id or userPrincipalName} 替换/me 并得到相同的错误。此外,似乎 Graph 确实正确地确定了用户“我”,因为错误消息说“资源 \'{My-UserID}\' 不存在......”我已经检查过这个 {My-UserID} 确实属于我在图形资源管理器中调用 /v1.0/users/{My-UserID} 返回我的用户详细信息。
    • 我怀疑 Graph 知道“我”是谁,因为在请求访问令牌时,它知道应用程序 ID 和租户 ID,因此它应该知道应用程序的管理员是谁,我还授予了管理员权限同意应用程序权限。此外,在解码接收到的访问令牌时,oid 字段确实正确显示了我的用户 ID。
    • 租户没有“管理员”之类的东西。如果您使用的是客户端凭据,那么您没有/me,如果您有/me,那么您没有使用客户端凭据并且很可能没有请求User.Read 范围。
    • 我同意,/me 对客户端凭据没有意义。我感到困惑的原因是/me 确实在错误中回复了一些 ID,我错误地认为这实际上是“我”。当我在 Graph Explorer 中调用 /v1.0/users/{the ID that /me error returns} 时,它也无济于事,它会返回我的用户配置文件。我现在知道无论你输入什么 ID,即/v1.0/users/123,仍然会返回我的用户配置文件,因为这是 Graph Explorer 可以访问的唯一配置文件。更有用的回复可能会出错!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多