Microsoft Graph API UnkownError

女生的网名这么多〃 提交于 2021-02-20 05:08:18

问题


What am I doing wrong? I want to list the files in the root of my OneDrive. But I always get a 401 Unauthorized.

I used Fiddler to track the requests and requesting the OAuth token seems to work fine. But when I try to request https://graph.microsoft.com/v1.0/me/drive/root/children I get Unauthorized as response with the code 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();

FYI: I am using .NET MVC 5 and I want to access my personal onedrive without user interaction. I seem to be a bit lost with what flow I should use for this.


回答1:


You are calling /me/drive/root/children endpoint, so you should use a user token rather than application token.

You are using auth code flow with:

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

Here you need to add .WithRedirectUri(redirectUri). See sample here.

And you should not use AcquireTokenForClient method here because it is requiring an application token with client credential flow.

If you are trying to call Microsoft Graph in a .net core MVC, please refer to this sample.

Acquire the access token:

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

If your application is .net MVC, please refer to this 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;
            }

UPDATE:

There are 2 scenes that we could connect to OneDrive without any further human interaction.

  1. Use client credential flow, which allow us to call Microsoft Graph with an application token. You need to add Application Permission into your Azure AD app. You should choose Client credentials provider and use GraphClient.Users["{userId or UPN}"].Drive.Root.Children instead of GraphClient.Me.Drive.Root.Children because there is no user(/me) in this case.

Corresponding code:

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. If you want to use GraphClient.Me.Drive.Root.Children but don't want sign-in interactively, you could choose Username/password provider, which uses OAuth 2.0 Resource Owner Password Credentials. This scene also uses user token rather than application token.

Please note that:

Microsoft recommends you do not use the ROPC flow. In most scenarios, more secure alternatives are available and recommended. This flow requires a very high degree of trust in the application, and carries risks which are not present in other flows. You should only use this flow when other more secure flows can't be used.

You need to add Delegated Permission in this case.

Corresponding code:

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();

UPDATE 2:

Unfortunately, both Client Credential flow and ROPC(Resource Owner Password Credentials) flow don't support personal accounts. For personal accounts, you have to use auth code flow I mentioned at the beginning and it requires you to sign-in interactively. In summary, it's impossible to access personal Onedrive without any further human interaction.



来源:https://stackoverflow.com/questions/65327473/microsoft-graph-api-unkownerror

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!