Доступ к файлам на сервере путем указания учетных данных

В нашей компании есть сервер документов точки общего доступа, где UNC выглядит примерно так: \\ theserver.ourdomain.com \ rootdirectory

В настоящее время этот диск сопоставлен с Z: \ на моем локальном компьютере. Для доступа к Z: \ вы должны указывать (каждый раз при входе в систему) учетные данные (в нашем случае это наши имя пользователя и пароль, с которыми мы вошли в систему) для доступа к папкам и файлам в корневом каталоге.

Я в ситуации, когда мне нужно скопировать файлы на сервер точки общего доступа. Я хочу иметь возможность копировать файлы на сервер без использования подключенного сетевого диска (не нужно указывать Z: \ в пути). Как я могу предоставить учетные данные, чтобы я мог выполнять базовые функции ввода-вывода, такие как GetDirectories (), GetFiles (), IO.File.Copy () и т. Д.?

Я изучил следующие вещи, но мне не удалось заставить их работать:

  1. вызов API LogonUser путем указания имени пользователя и пароля в виде обычного текста, затем взятия токена из этого вызова и олицетворения этого пользователя с помощью нового экземпляра класса WindowsIdentity. Удалось получить токен, но имитация не сработала. Продолжал получать ошибки отказа в доступе.
  2. CredUIPromptForCredentials / < вызовы API href = "http://msdn.microsoft.com/en-us/library/windows/desktop/aa375178%28v=vs.85%29.aspx" rel = "nofollow"> CredUIPromptForWindowsCredentials, но я понимаю, что это только для причудливого пользовательского интерфейса Windows, в который вы можете ввести свои учетные данные и на самом деле ничего не делать.

    <DllImport("advapi32.dll", SetLastError:=True)> _
    Private Shared Function LogonUser(lpszUsername As String, lpszDomain As String, _
                                              lpszPassword As String, dwLogonType As Integer, _
                                              dwLogonProvider As Integer, ByRef phToken As IntPtr) As Boolean
    End Function
    
    <DllImport("kernel32.dll", CharSet:=CharSet.Auto)> _
    Private Shared Function CloseHandle(handle As IntPtr) As Boolean
    End Function
    
    '// logon types
    Public Const LOGON32_LOGON_NETWORK As Integer = 3
    Public Const LOGON32_LOGON_NEW_CREDENTIALS As Integer = 9
    
    '// logon providers
    Public Const LOGON32_PROVIDER_WINNT50 As Integer = 3
    Public Const LOGON32_PROVIDER_WINNT40 As Integer = 2
    Public Const LOGON32_PROVIDER_WINNT35 As Integer = 1
    Public Const LOGON32_PROVIDER_DEFAULT As Integer = 0
    
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim token = IntPtr.Zero
        Dim success = LogonUser("username", "domain", "password", _
                                LOGON32_LOGON_NEW_CREDENTIALS, _
                                LOGON32_PROVIDER_DEFAULT, token)
    
        If Not success Then
            Me.RaiseLastWin32Error()
        End If
    
        Using identity = New WindowsIdentity(token)
            Using impersonated = identity.Impersonate()
                Try
                    Dim info = New DirectoryInfo("\\theserver.ourdomain.com\rootdirectory\")
                    Dim files = info.GetDirectories()
                Catch ex As Exception
                Finally
                    impersonated.Undo()
                End Try
                If Not CloseHandle(token) Then
                    Me.RaiseLastWin32Error()
                End If
            End Using
        End Using
    
    End Sub
    
    Private Sub RaiseLastWin32Error()
        Dim hr = Marshal.GetLastWin32Error()
        Dim ex = Marshal.GetExceptionForHR(hr)
    
        If ex IsNot Nothing Then
            Throw ex
        End If
        Throw New SystemException(String.Format("Call resulted in error code {0}", hr))
    End Sub
    

person test    schedule 12.06.2012    source источник
comment
Дополнительный ресурс MSDN: msdn.microsoft.com/en-us/library/chf6fbt4 .aspx. Понимая, что вы уже пробовали это (№1 в своем сообщении), вам может потребоваться показать некоторый код, чтобы диагностировать, почему вы получаете исключения.   -  person Cᴏʀʏ    schedule 13.06.2012
comment
Добавлен код в сообщение выше   -  person test    schedule 13.06.2012
comment
Код в другом сообщении и примере MSDN оба немного отличаются и сложнее, чем то, что вы пробовали. Дайте им обоим шанс и доложите об этом.   -  person Cᴏʀʏ    schedule 13.06.2012
comment
Пробовал, и они не работают. По-прежнему возникает ошибка отказа в доступе. Думаю, что один из нас чего-то не понимает. Мне не нужно выдавать себя за себя для доступа к серверу, я уже вошел в систему как пользователь, которому я хочу получить доступ к файлам. Должно быть что-то, чего мне не хватает.   -  person test    schedule 13.06.2012
comment
Что произойдет, если вы запустите приложение runas.exe /netonly /user:domain\username pathtoyourexe.exe?   -  person Cᴏʀʏ    schedule 13.06.2012


Ответы (2)


Это не прямой ответ на ваш вопрос, это совершенно другой подход. Если это не работает в вашей ситуации, извините за беспокойство, но рассматривали ли вы возможность использования веб-служб SharePoint для загрузки файлов и получения информации?

Я предлагаю этот подход по нескольким причинам:

  1. Проблема, с которой вы столкнулись, может быть вызвана тем, что SharePoint реализует WebDav, который может быть не на 100% совместим с System.IO. Я здесь не специалист по внутренностям, насчет совместимости точно не знаю, но это кажется правдоподобным.
  2. Имеющееся у вас UNC-расположение можно легко преобразовать в URL-адрес, который требуется веб-службе.
  3. Вы можете установить учетные данные прямо на прокси-сервере, и это может быть проще. (хотя мы выполняем эти вызовы с другого веб-сервера, поэтому учетные данные пула приложений в этом примере для нас достаточно хороши)

Вот на всякий случай очищенный и упрощенный код:

// location takes the form http://server.name.com/site/library/folder/document.ext

public string UploadDocument(string location, byte[] fileContents)
{
    var result = String.empty;
    var destination = new string[1];
    destination[0] = location;
    var fileName = Path.GetFileName(location);
    var fieldInfo = new FieldInformation[0];
    CopyResult[] copyResults;

    _copyService.Url = "http://server.name.com/_vti_bin/Copy.asmx";
    _copyService.Credentials = CredentialCache.DefaultCredentials;
    _copyService.CopyIntoItems(fileName, destination, fieldInfo, fileContents, out copyResults);

    var errorCode = copyResults[0].ErrorCode;
    if (errorCode != CopyErrorCode.Success)
    {
        if (errorCode == CopyErrorCode.DestinationCheckedOut)
            result = "File is currently checked out. Please try again later.";
        else
            result = "Error uploading content.";
    }

    return result;
}

_copyService - это внедряемая нами зависимость, реализация которой во время выполнения представляет собой прокси-сервер, созданный инструментами Visual Studio из веб-службы SharePoint Copy.asmx.

Вы также можете получить содержимое папки и метаданные документа с помощью веб-службы Lists.asmx. Самым большим недостатком этого подхода является то, что для запроса информации требуются некоторые знания CAML, а обработка результатов не так проста. Но службы достаточно документированы в MSDN, и все операции работают в нашем приложении.

person Chuck    schedule 12.06.2012
comment
Спасибо за ответ. Я могу получить доступ к файлам и каталогам с помощью кода, если я (через проводник) предоставлю свой пароль и имя пользователя подключенному сетевому диску, если он запрашивает. Меня также беспокоят проблемы с производительностью, если я пойду по маршруту, который вы предлагаете. - person test; 13.06.2012
comment
Интересный. Тогда мне будет любопытно найти решение самому, потому что я понимаю, откуда вы исходите с точки зрения производительности. - person Chuck; 13.06.2012

Что ж, я смог решить эту проблему с помощью API WNetAddConnection2. Этот API также используется для сопоставления сетевых дисков, однако вы можете вызвать этот метод без указания буквы диска, чтобы он просто добавил соединение.

Скажем, например, у вас есть диск X: сопоставлен с \\ server \ share. Допустим также, что для доступа к файлам на сервере требуется имя пользователя и пароль. Когда вы перезапустите Windows 7, вы, вероятно, потеряете это соединение (вы получите уведомление о том, что Windows не удалось повторно подключить некоторые сетевые диски). Если у вас есть приложение, которому требуется доступ к файлам этого сервера, и вы пытаетесь получить к нему доступ, не предоставляя свои учетные данные, вы получите исключения, запрещающие доступ. Если вы выполните успешный вызов WNetAddConnection2, он не только исправит ваш несопоставленный сетевой диск, вы также сможете получить доступ к файлам / каталогам через пространство имен System.IO.

Мы используем Sharepoint, и у меня это сработало. Спасибо и другим парням за ответы.

person test    schedule 13.06.2012