【问题标题】:How to get the Access Token for OneDrive API from Angular如何从 Angular 获取 OneDrive API 的访问令牌
【发布时间】:2021-07-01 09:26:48
【问题描述】:

我有一个允许用户上传文件的 Angular 应用程序。我打算使用OneDrive API(我为应用程序设置的OneDrive 帐户)将这些文件存储在OneDrive 中。

我知道我们必须使用OAuth2.0 从网络服务器获取访问令牌并将该令牌用作不记名令牌以使用 API 来管理我在 OneDrive 中的文件。

如何在我的 Angular 应用中获取此访问令牌?

我需要获取访问令牌而不重定向到登录页面(无需用户交互)。 但在后台。

我尝试使用以下 URL 在 POSTMAN 中获取访问令牌。

https://login.microsoftonline.com/{Tenant_ID}/oauth2/token

我试过了,

  • 客户端凭据流。
  • 资源所有者流程。
  • 隐式流。

Angular 中的隐式流函数 (我已经硬编码了要测试的 URL 和值)

    getToken() {
    var msFormData = new FormData();
    msFormData.append('grant_type', 'client_credentials');
    msFormData.append('client_id', 'client_id');
    msFormData.append('client_secret', 'client_secret');
    msFormData.append('resource', 'https://graph.microsoft.com');

    return this.http.post("https://login.microsoftonline.com/{id}/oauth2/token", msFormData);
}

所有三个都在工作并且能够获得令牌。 当我在 Angular 中尝试隐式流时,我收到了 CORS 错误。 (无论如何我都不能使用隐式,因为客户端密码会被暴露)。

当尝试使用Resource_owner 流程时,我得到了SPO license 错误信息。如果我使用user flow 并检索访问权限 来自重定向 URL 的令牌。我可以使用 Graph API 访问令牌以获取驱动器项目。所以我知道我不需要 SPO 许可。(也许)

如果这不是我可以在后端创建服务以获取访问令牌/刷新令牌并使用 API 将其提供给 Angular 应用程序的最佳方式,那么用户可以从浏览器上传文件。但是从上述流程中获得的访问令牌给了我一个 SPO 错误。


更新: 我发现要访问一个驱动器,我们需要一个委托访问令牌。这与 client_credenttial 流有何不同?以及如何获得它们?

【问题讨论】:

  • // 您可以使用该示例以静默方式请求访问令牌,并且异步 getAccessToken() 工作: Promise { let result = await this.msalService.acquireTokenSilent(OAuthSettings) .catch(( reason) => { this.alertsService.addError('获取令牌失败', JSON.stringify(reason, null, 2)); }); if (result) { // 临时在错误框中显示 token this.alertsService.addSuccess('Token acquire', result.accessToken);返回result.accessToken; } // 无法获取令牌 this.authenticated = false;返回空值;
  • 顺便说一句,我使用了来自 step-by-step Angular SPA example uses Microsoft Graph API and OneDrive API 的代码示例。它对我有用。
  • 但是这里我们只传递作用域。 Id, Secret.?我想在不显示登录表单的情况下将文件上传到我的一个驱动器
  • 如果您需要委托令牌,则不能使用客户端凭据流。客户端凭证流只能获取应用token,即没有用户登录!
  • 有没有办法在不交互的情况下获取委托令牌

标签: angular oauth-2.0 azure-active-directory microsoft-graph-api pkce


【解决方案1】:

要在没有用户交互的情况下获得有效的图形令牌,您可以使用以下请求。但是请注意,这意味着在您的客户端代码中存储了客户端密码。有了这个,用户就可以请求一个有效的应用程序令牌,并可以访问应用程序范围内允许的任何内容。

因此,就像名称已经说明的那样,客户端密码应该保密,不能在客户端站点的代码中使用。最好有一个自己的 REST api,它发送以下请求并将令牌返回给您的 Angular 应用程序。如何保护此 API 取决于您。

非交互式用户令牌

var settings = {
  "async": true,
  "crossDomain": true,
  "url": `https://login.microsoftonline.com/${tenantId}/oauth2/token`,
  "method": "POST",
  "headers": {
    "content-type": "application/x-www-form-urlencoded",
    "cache-control": "no-cache"
  },
  "data": {
    "client_id": `${clientId}`,
    "client_secret": ${clientSecret}``,
    "resource": "https://graph.microsoft.com/",
    "username": `${username}`,
    "password": `${password}`,
    "grant_type": "password",
    "scope": "openid"
  }
}

$.ajax(settings).done(function (response) {
  console.log(response);
});

不过,您可以将上述请求转换为您的具体语言。但作为一项特殊服务,我将上述代码重写为您给定的代码(未经测试):

getToken() {
    var msFormData = new FormData();
    msFormData.append('clientId', `${clientId}`);
    msFormData.append('client_secret', `${clientSecret}`);
    msFormData.append('resource', 'https://graph.microsoft.com');
    msFormData.append('username', `${username}`);
    msFormData.append('password', `${password}`);
    msFormData.append('grant_type', 'password');
    msFormData.append('scope', 'openid');
    
    return this.http.post(`https://login.microsoftonline.com/${tenantId}/oauth2/token`, msFormData);
}

非交互式应用令牌

var settings = {
  "async": true,
  "crossDomain": true,
  "url": `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`,
  "method": "POST",
  "headers": {
    "content-type": "application/x-www-form-urlencoded",
    "cache-control": "no-cache",
  },
  "data": {
    "grant_type": "client_credentials",
    "scope": "https://graph.microsoft.com/.default",
    "client_id": `${clientId}`,
    "client_secret": `${clientSecret}`
  }
}

$.ajax(settings).done(function (response) {
  console.log(response);
});

您也可以直接使用变量本身,而不是使用仅包含变量的反引号字符串。但我选择这种风格是为了更好地强调,这些参数必须自己提供。

【讨论】:

  • 谢谢,我需要以应用程序的身份登录。所以我尝试使用应用程序名称作为用户名。没有用
  • @JeffinJ:对于应用程序令牌,授权类型必须不同,并且不需要用户名或密码。
  • 是的,感谢您更新的答案。有什么方法可以克服这个请求的 CORS 错误。我尝试设置代理。不工作。
【解决方案2】:

委托的令牌通常称为user token,而您通过客户端凭证流获得的令牌是application token。它们之间的唯一区别是是否有用户登录。

如果你想获得一个委托令牌,必须登录用户。不管是interactive login还是non-interactive login,用户都必须登录!

另外,您需要将/tenant id端点更改为/common端点以避免租户级登录。

【讨论】:

  • 我已经尝试过非交互式流程ropc 但是在使用访问令牌获取一个驱动器时,我收到此错误:Tenant does not have a SPO license
  • @JeffinJ 您的帐户是个人帐户还是工作帐户?
  • @JeffinJ 文档中有特别说明ropc flow不支持个人账户。您只能使用授权代码流来获取委托令牌。
  • @JeffinJ 尝试将/tenant id 端点更改为/common 端点以避免租户级登录。
  • @JeffinJ 发现了一个类似的问题,确实和我想的一样,就是只能使用auth code flow。见:stackoverflow.com/questions/66787193/…
【解决方案3】:

在一个驱动器上以角度上传文件涉及三个步骤,

  1. 针对 Azure AD 对最终用户进行身份验证并获取 id_token
  2. 获取图形 API 令牌
  3. 为一个驱动器调用文件上传API

第一步是用户使用 Azure AD 进行身份验证,这将以交互方式进行。我们可以使用 MSAL 库来获取 id 令牌。下面提到的链接包含所有文档,

https://docs.microsoft.com/en-us/graph/auth-v2-user#1-register-your-app

在 Azure AD 应用程序的第二步之前,我们需要映射配置受保护的资源映射并在那里添加图形 API url,范围为 “Files.ReadWrite.All”。然后尝试使用上述链接中提到的第 3 步在后台获取图形 api 令牌的令牌。 Graph API 令牌已使用客户端密钥生成。

一旦我们收到 Graph API 令牌,我们就可以发送文件。为此,您可以使用下面提到的链接,

how to specify the stream to upload a file to onedrive using ms graph

【讨论】:

  • 感谢您的回答。但是要考虑的事情很少。最终用户没有 MS 帐户。我需要将文件存储到我以我的应用程序名称创建的帐户中。因此,使用登录页面登录(交互式)不是一种选择。我已经尝试了 client_credential 和资源所有者流程并获得了令牌。使用 RO 流,当我使用访问令牌时,我从 AD 获取用户,但是当访问驱动器的 /me 时,我没有收到 SPO 许可证错误。
  • 在 Azure AD 中,我们有一个功能“Azure AD B2C”,它允许拥有非 MS 帐户的最终用户对 Azure AD 进行身份验证和授权。因此,如果我们配置该核心问题将得到解决。请使用下面提到的链接:link
  • 所以我应该创建一个新的 AAD B2c 目录。然后注册一个应用,使用资源所有者流获取访问令牌?
  • 我们无法在没有订阅的情况下创建 Azure AD B2C,我已注册订阅并按照您所说的做了。仍然收到Tenant does not have a SPO license. 的错误
  • 是的,我在 MSDN 上查找了该错误,但没有得到任何正确答案。但有一点我注意到 onedrive 是 office 365 的一部分,我们可能需要将 office365 订阅给租户link
【解决方案4】:

如果其他人有类似的问题,几周前,当我试图在我的 Angular 应用程序中做与 OP 相同的事情时。由于我工作的公司使用个人 Microsoft 帐户,因此无法使用非交互式流程[1][2] 访问公司的一个驱动器。因此,由于公司员工已经将公司的一个驱动器作为共享文件夹,我们正在寻找一种新的登录解决方案,并且我们只能使用交互方式来访问 Graph API。我们接受 MSAL 并更改我们的登录方法以使用员工的个人 Microsoft 帐户。

所以要登录,我们使用@azure/msal-angular,它还提供 HTTP 拦截器和弹出策略。因此,员工使用Oauth2 Token Flow 在弹出窗口中填写其 Microsoft 凭据。登录后,MSAL_INTECEPTOR 会刷新我们的令牌并在向 Graph API 发出请求时放置授权代码。我们代码中的更改在这 2 个提交[3][4] 中进行了描述。准备好这部分后,现在我们可以向 Onedrive API 发出请求,将文件上传到所有员工拥有的公司共享文件夹。我在这里分享了一些关于上传到共享文件夹的技巧:Microsoft Graph: Uploading files to shared with me folder on OneDrive?

我真的很喜欢我拥有的 MSAL 的结果,公司员工也喜欢直接与 Onedrive 集成。因为他们只需要登录我们的应用程序一次就可以了。

我在这里分享了一步邮递员Oauth2 Code Flow练习Onedrive文件上传到个人账户:Tenant does not have a SPO license

【讨论】:

    猜你喜欢
    • 2016-12-18
    • 1970-01-01
    • 1970-01-01
    • 2019-03-03
    • 2023-04-05
    • 2012-10-27
    • 2015-05-11
    • 2017-02-14
    • 1970-01-01
    相关资源
    最近更新 更多