Я не могу получить доступ к файлу Excel на сайте SharePoint, несанкционированное исключение, код ошибки 401

#c# #sharepoint #httpclient #ntlm #csom

#c# #sharepoint #httpclient #ntlm #csom

Вопрос:

Я пытаюсь получить доступ к файлу Excel, расположенному на сайте в Sharepoint. У меня нет возможности вносить изменения со стороны сервера. Я могу получить доступ к файлу из Chrome, когда я ввожу ссылку, файл автоматически загружается. Но когда я попытался загрузить с помощью кода C # (.Net framework 4.6.1), я получил несанкционированное исключение, код ошибки 401. Я попробовал несколько вещей. Сначала я попробовал CSOM (объектная модель Sharepoint на стороне клиента). Код выглядит следующим образом

 static void Main(string[] args)
        {
            var link2 = @"File link";
            ClientContext context = new ClientContext(link2);

            Web web = context.Web;
            context.ExecutingWebRequest  = clientContext_ExecutingWebRequest;
            context.Credentials = CredentialCache.DefaultCredentials;
            context.Load(web);

            ExceptionHandlingScope scope = new ExceptionHandlingScope(context);

            using (scope.StartScope())
            {
                using (scope.StartTry())
                {
                    context.ExecuteQuery();// <- Unautherized exception
                    Console.WriteLine(web.Title);
                }
                using (scope.StartCatch())
                {
                    Console.WriteLine(scope.ServerStackTrace);
                }

            }

            Console.ReadLine();

        }
        static void clientContext_ExecutingWebRequest(object sender, WebRequestEventArgs e)
        {
            e.WebRequestExecutor.WebRequest.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
        }
  

После этого я вернулся к традиционному методу и использовал HttpClient. Код следует

 static void Main(string[] args)
        {
            var link = @"sitelink";
            var link2 = @"filelink";

            var credential = new CredentialCache
            {
                { new Uri(link2),"NTLM", CredentialCache.DefaultNetworkCredentials}
            };

            var options = new HttpClientHandler
            {
                Credentials = credential
            };

            //var client = new HttpClient(options);

            using (var client = new HttpClient(options))
            {
                var requestMessage = new HttpRequestMessage();
                requestMessage.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
                requestMessage.Method = HttpMethod.Get;
                requestMessage.RequestUri = new Uri(link2);
                requestMessage.Headers.Add("Use-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36");
                var response = client.SendAsync(requestMessage).Resu<
                Console.WriteLine(JsonConvert.SerializeObject(response,Formatting.Indented));
                if (response != null amp;amp; response.IsSuccessStatusCode)// <- Status false, Unautherized is in the response header
                {
                    using (var reader = new io.StreamReader(response.Content.ReadAsStreamAsync().Result))
                    {
                        io.File.WriteAllText(@"C:UsersNamesourcereposTestExcel.xlsx", reader.ReadToEndAsync().Result );
                    }
                        
                }
            }

            Console.WriteLine("DOne");
        }
  

Я новичок в sharepoint и ценю любую помощь. Заранее спасибо.
\\\\\\\\\\\\\\\\\\\
Еще одна попытка

 var link2 = @"file link";

            var client = new HttpClient(new HttpClientHandler
            {
                UseDefaultCredentials = true
            });

            io.Stream resultStream = null;
            try
            {
                resultStream = client.GetStreamAsync(link2).Resu<
                var reader = new io.StreamReader(resultStream);
                io.File.WriteAllText(@"C:UsersNamesourcereposTestExcel.xlsx", reader.ReadToEndAsync().Result);
                reader.Close();
            } catch (Exception e)
            {
                Console.WriteLine(JsonConvert.SerializeObject(e,Formatting.Indented));
            }
            
            Console.WriteLine("Done");
            Console.ReadLine();
  

Завершите сериализованный объект исключения

 {
  "ClassName": "System.AggregateException",
  "Message": "One or more errors occurred.",
  "Data": null,
  "InnerException": {
    "ClassName": "System.Net.Http.HttpRequestException",
    "Message": "Response status code does not indicate success: 401 (Unauthorized).",
    "Data": null,
    "InnerException": null,
    "HelpURL": null,
    "StackTraceString": null,
    "RemoteStackTraceString": null,
    "RemoteStackIndex": 0,
    "ExceptionMethod": null,
    "HResult": -2146233088,
    "Source": null,
    "WatsonBuckets": null,
    "SafeSerializationManager": {
      "m_serializedStates": [
        {}
      ]
    },
    "CLR_SafeSerializationManager_RealType": "System.Net.Http.HttpRequestException, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken="
  },
  "HelpURL": null,
  "StackTraceString": "   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)rn   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)rn   at System.Threading.Tasks.Task`1.get_Result()rn   at SharePointTrail.Program.Main(String[] args) in C:\Users\name\source\repos\SharePointTrail\SharePointTrail\Program.cs:line 27",
  "RemoteStackTraceString": null,
  "RemoteStackIndex": 0,
  "ExceptionMethod": "8nThrowIfExceptionalnmscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=nSystem.Threading.Tasks.TasknVoid ThrowIfExceptional(Boolean)",
  "HResult": -2146233088,
  "Source": "mscorlib",
  "WatsonBuckets": null,
  "InnerExceptions": [
    {
      "ClassName": "System.Net.Http.HttpRequestException",
      "Message": "Response status code does not indicate success: 401 (Unauthorized).",
      "Data": null,
      "InnerException": null,
      "HelpURL": null,
      "StackTraceString": null,
      "RemoteStackTraceString": null,
      "RemoteStackIndex": 0,
      "ExceptionMethod": null,
      "HResult": -2146233088,
      "Source": null,
      "WatsonBuckets": null,
      "SafeSerializationManager": {
        "m_serializedStates": [
          {}
        ]
      },
      "CLR_SafeSerializationManager_RealType": "System.Net.Http.HttpRequestException, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken="
    }
  ]
}
  

Обновить
Sharepoint размещен в office 365.
Кажется, Office 365 заботится об авторизации. Когда я проверяю в Chrome dev tool, в исходном файле я нахожу пару файлов js (имена, которые я не могу здесь упомянуть).

Комментарии:

1. Это может быть связано с тем, что в Chrome вы уже вошли в систему. Вот почему вы не получаете 401 в Chrome, но при использовании C # вы еще не авторизованы. Для этого вам необходимо иметь токен доступа к вашему Sharepoint и прикрепить его в качестве заголовка к вашему запросу.

2. Спасибо @robalem. Но я совершенно новичок в sharepoint. Поэтому, пожалуйста, помогите мне понять, как я получу токен доступа? должен ли я выполнить обмен Oauth2? Как сохранить этот токен на протяжении всего срока службы приложения?

3. @AdityaNadig опубликованные вами фрагменты кода содержат много строк, которые выглядят как случайные попытки заставить что-то работать. Документы в SharePoint доступны по их URL. Вам не нужно более 3-4 строк, чтобы создать HttpClient с авторизацией Windows, выполнить HttpClient.GetStreamAsync и записать файл на диск. Весь добавленный вами код и заголовки могут только вызывать проблемы

4. Не объясняя все это самостоятельно, взгляните на это руководство , в котором описывается, как получить токен доступа из Sharepoint Online. После получения токена вы можете добавить его к своему запросу.

5. Что касается кода CSOM, он не имеет особого смысла и снова выглядит как случайный код. ClientContext используется для подключения к сайту, а не для загрузки документа. Заголовки, области видимости и т.д. Не имеют смысла, и опять же, дополнительные заголовки будут вызывать только проблемы. Вы проверили документацию CSOM и примеры?