Вопрос или проблема
Я пытаюсь выполнить операции с файлами (загрузка, скачивание, удаление) в файловой системе пользователя, используя подделку учетной записи в C#. После исследований я наткнулся на метод WindowsIdentity.RunImpersonated
, который использую для делегирования полномочий для операций с файлами.
Однако я сталкиваюсь с ошибкой «Доступ запрещен». Ниже приведен соответствующий код, который я реализовал:
public class ImpersonationManager
{
private SafeAccessTokenHandle _safeAccessTokenHandle;
private readonly string _domainName;
private readonly string _userName;
private readonly string _password;
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, out SafeAccessTokenHandle phToken);
public ImpersonationManager(string domainName, string userName, string password)
{
_domainName = domainName;
_userName = userName;
_password = password;
}
public SafeAccessTokenHandle GetSafeAccessTokenHandle()
{
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
try
{
bool returnValue = LogonUser(_userName, _domainName, _password,
LOGON32_PROVIDER_DEFAULT, LOGON32_LOGON_INTERACTIVE,
out _safeAccessTokenHandle);
if (!returnValue)
{
int ret = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(ret, $"LogonUser не удался с кодом ошибки : {ret}");
}
}
catch (Exception ex)
{
throw;
}
return _safeAccessTokenHandle;
}
}
public async Task<bool> UploadFileAsync(string filePath = null, File file = null, Stream fileStream = null)
{
if (file == null)
throw new ArgumentNullException(nameof(file));
if (fileStream == null)
throw new ArgumentNullException(nameof(fileStream));
SafeAccessTokenHandle safeAccessTokenHandle = GetSafeAccessTokenHandleAsync();
WindowsIdentity.RunImpersonated(safeAccessTokenHandle,() =>
{
var fileName = file.FileName;
try
{
using (FileStream destinationStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
fileStream.CopyTo(destinationStream);
return true;
}
}
catch (Exception ex)
{
throw;
}
});
return true;
}
Ответ или решение
Проблема "Access Denied" при использовании WindowsIdentity.RunImpersonated для операций с файлами
При использовании метода WindowsIdentity.RunImpersonated
для выполнения операций с файлами от имени другого пользователя, ошибка "Access Denied" может возникать по нескольким причинам. Давайте разберем основные аспекты, на которые следует обратить внимание, и предложим подходы для устранения этой проблемы.
1. Проверьте права пользователя
Прежде всего, убедитесь, что пользователь, от имени которого вы выполняете операции, действительно имеет необходимые права для доступа к файлам или каталогам на файловой системе. Убедитесь, что:
- Путь к файлу или каталогу доступен для этого пользователя.
- У пользователя есть права на чтение, запись или удаление файлов, в зависимости от операции, которую вы выполняете.
2. Проверьте корректность логина
При вызове LogonUser
убедитесь, что передаете корректные учетные данные (домен, имя пользователя и пароль). Ошибка в одной из этих данных может вызвать несанкционированный доступ. Вы можете проверить переменные на предмет правильности ввода.
3. Использование правильного типа входа
В вашем коде используется LOGON32_LOGON_INTERACTIVE
, который может не подойти для всех ситуаций. Возможно, вам понадобится использовать:
LOGON32_LOGON_NEW_CREDENTIALS
для делегирования учетных данных.LOGON32_LOGON_SERVICE
, если вы обладаете необходимыми правами.
Измените часть кода, где происходит вызов LogonUser
, на:
const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
// ...
bool returnValue = LogonUser(_userName, _domainName, _password,
LOGON32_PROVIDER_DEFAULT, LOGON32_LOGON_NEW_CREDENTIALS,
out _safeAccessTokenHandle);
4. Обработка SafeAccessTokenHandle
Убедитесь, что вы корректно обрабатываете объект SafeAccessTokenHandle
. Необходимо убедиться в том, что он не равен null
перед его использованием в RunImpersonated
.
5. Синхронизация кода
Ваш метод UploadFileAsync
содержит асинхронный код, но не использует async
и await
должным образом внутри RunImpersonated
. Убедитесь, что ваш код может асинхронно обрабатывать ваши требования. Например, вы можете использовать Task.Run
:
public async Task<bool> UploadFileAsync(string filePath = null, File file = null, Stream fileStream = null)
{
if (file == null)
throw new ArgumentNullException(nameof(file));
if (fileStream == null)
throw new ArgumentNullException(nameof(fileStream));
SafeAccessTokenHandle safeAccessTokenHandle = GetSafeAccessTokenHandleAsync();
bool result = await Task.Run(() =>
{
return WindowsIdentity.RunImpersonated(safeAccessTokenHandle, () =>
{
try
{
using (FileStream destinationStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
fileStream.CopyTo(destinationStream);
}
return true;
}
catch (Exception ex)
{
// Логирование ошибки для отладки
Console.WriteLine(ex.Message);
throw;
}
});
});
return result;
}
6. Логгирование ошибок
Для улучшения отладки добавьте в ваш код логирование ошибок, чтобы было легче выявлять, на каком этапе происходит сбой. Это поможет вам более точно определить, что именно вызывает ошибку "Access Denied".
Заключение
Следуя вышеуказанным шагам и рекомендациям, вы сможете диагностировать и устранить проблему "Access Denied" при использовании WindowsIdentity.RunImpersonated
. Убедитесь, что ваши учетные данные, права и логика обработки кода соответствуют заданным требованиям. Если ошибка продолжает возникать, рассмотрите возможность гибкой настройки прав доступа на уровне файловой системы или обратитесь к системному администратору для дополнительной помощи.