【问题标题】:Microsoft Graph API UnkownErrorMicrosoft Graph API UnkownError
【发布时间】:2020-12-16 16:41:25
【问题描述】:

我做错了什么?我想列出 OneDrive 根目录中的文件。但我总是得到 401 Unauthorized

我使用 Fiddler 来跟踪请求,并且请求 OAuth 令牌似乎工作正常。但是,当我尝试请求 https://graph.microsoft.com/v1.0/me/drive/root/children 时,我得到 Unauthorized 作为响应,代码为 UnknownError

private static GraphServiceClient GetAuthenticatedGraphClient()
    {
        List<string> scopes = new List<string>
        {
            "https://graph.microsoft.com/.default",
        };


        var cca = ConfidentialClientApplicationBuilder.Create(CLIENT_ID)
                                                .WithAuthority(AadAuthorityAudience.PersonalMicrosoftAccount)
                                                .WithClientSecret(SECRET)
                                                .Build();

        GraphServiceClient graphServiceClient =
            new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
                {
                    // Retrieve an access token for Microsoft Graph (gets a fresh token if needed).
                    var authResult = await cca.AcquireTokenForClient(scopes).ExecuteAsync();

                    // Add the access token in the Authorization header of the API
                    requestMessage.Headers.Authorization =
                        new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
                })
            );

        return graphServiceClient;
    }

var drive = GraphClient.Me.Drive.Root.Children.
Request().
GetAsync();

仅供参考:我正在使用 .NET MVC 5,我想在没有用户交互的情况下访问我的 个人 onedrive。我似乎对我应该为此使用什么流程感到有点迷茫。

【问题讨论】:

  • 我会检查jwt.ms 中的令牌,看看您是否拥有必要的权限/角色/范围。
  • 你的应用是什么类型的?它是网络应用还是控制台应用?
  • 它是.NET MVC 应用程序(.NET Framework)

标签: c# azure-active-directory microsoft-graph-api


【解决方案1】:

您正在调用/me/drive/root/children 端点,因此您应该使用用户令牌而不是应用程序令牌。

您正在使用auth code flow

var cca = ConfidentialClientApplicationBuilder.Create(CLIENT_ID)
              .WithAuthority(AadAuthorityAudience.PersonalMicrosoftAccount)
              .WithClientSecret(SECRET)
              .Build();

这里需要添加.WithRedirectUri(redirectUri)。参见示例here

您不应该在这里使用AcquireTokenForClient 方法,因为它需要带有client credential flow 的应用程序令牌。

如果您尝试在 .net 核心 MVC 中调用 Microsoft Graph,请参阅此sample

获取访问令牌:

string token = await _tokenAcquisition
    .GetAccessTokenForUserAsync(GraphConstants.Scopes);

如果你的应用是.net MVC,请参考这个document

var idClient = ConfidentialClientApplicationBuilder.Create(appId)
                .WithRedirectUri(redirectUri)
                .WithClientSecret(appSecret)
                .Build();

            string message;
            string debug;

            try
            {
                string[] scopes = graphScopes.Split(' ');

                var result = await idClient.AcquireTokenByAuthorizationCode(
                    scopes, notification.Code).ExecuteAsync();

                message = "Access token retrieved.";
                debug = result.AccessToken;
            }

更新:

有 2 个场景可以连接到 OneDrive,无需任何进一步的人工交互。

  1. 使用client credential flow,它允许我们使用应用程序令牌调用 Microsoft Graph。您需要将应用程序权限添加到您的 Azure AD 应用程序中。您应该选择Client credentials provider 并使用GraphClient.Users["{userId or UPN}"].Drive.Root.Children 而不是GraphClient.Me.Drive.Root.Children,因为在这种情况下没有用户(/me)。

对应代码:

IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithTenantId(tenantID)
    .WithClientSecret(clientSecret)
    .Build();

ClientCredentialProvider authProvider = new ClientCredentialProvider(confidentialClientApplication);

GraphServiceClient graphClient = new GraphServiceClient(authProvider);

var children = await graphClient.Users["{userId or UPN}"].Drive.Root.Children
    .Request()
    .GetAsync();
  1. 如果您想使用GraphClient.Me.Drive.Root.Children,但不想以交互方式登录,您可以选择Username/password provider,它使用OAuth 2.0 Resource Owner Password Credentials。此场景还使用用户令牌而不是应用程序令牌。

请注意:

Microsoft 建议您不要使用 ROPC 流程。在大多数情况下, 可以使用并推荐更安全的替代方案。这个流 要求对应用程序有非常高的信任度,并携带 其他流动中不存在的风险。你应该只使用这个 当其他更安全的流无法使用时流。

在这种情况下,您需要添加 Delegated Permission

对应代码:

IPublicClientApplication publicClientApplication = PublicClientApplicationBuilder
            .Create(clientId)
            .WithTenantId(tenantID)
            .Build();

var email = "{your username}";
var str = "{your password}";
var password = new SecureString();
foreach (char c in str) password.AppendChar(c);

UsernamePasswordProvider authProvider = new UsernamePasswordProvider(publicClientApplication, scopes);

GraphServiceClient graphClient = new GraphServiceClient(authProvider);

var children= await graphClient.Me.Drive.Root.Children.Request()
                .WithUsernamePassword(email, password)
                .GetAsync();

更新 2:

很遗憾,客户端凭据流和 ROPC(资源所有者密码凭据)流都不支持个人帐户。对于个人帐户,您必须使用我在开头提到的身份验证代码流程,并且需要您交互式登录。总之,如果没有任何进一步的人工交互,就不可能访问个人 Onedrive。

【讨论】:

  • 重定向 uri 的用途是什么?我只是想存储客户端密码并连接到 OneDrive,而无需任何进一步的人工交互。
  • @stickfigure4 请参阅我的回答中的 UPDATE
  • 我尝试了第一个选项,但没有成功。如果我尝试获取用户,例如我得到“Authorization_RequestDenied”。但是,如果我理解正确,这不是因为这不适用于个人帐户吗?
  • @stickfigure4 不幸的是,客户端凭据流和 ROPC(资源所有者密码凭据)流都不支持个人帐户。对于个人帐户,您必须使用我在开头提到的身份验证代码流程,并且需要您交互式登录。总之,如果没有任何进一步的人工交互,就不可能访问个人 onedrive。在我的回答中更新了它。如果它有帮助,您可以接受它作为答案。谢谢。
  • 是否有其他替代方案可以实现?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
  • 2022-08-26
  • 2019-01-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多