C # Проверка, имеет ли пользователь право на запись в папку - PullRequest
169 голосов
/ 11 сентября 2009

Мне нужно проверить, может ли пользователь записать в папку, прежде чем пытаться это сделать.

Я реализовал следующий метод (в C # 2.0), который пытается получить разрешения безопасности для папки, используя Directory.GetAccessControl () метод.

private bool hasWriteAccessToFolder(string folderPath)
{
    try
    {
        // Attempt to get a list of security permissions from the folder. 
        // This will raise an exception if the path is read only or do not have access to view the permissions. 
        System.Security.AccessControl.DirectorySecurity ds = Directory.GetAccessControl(folderPath);
        return true;
    }
    catch (UnauthorizedAccessException)
    {
        return false;
    }
}

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

Будет ли мой метод проверки правильности работы текущего пользователя с правами на запись?

Ответы [ 18 ]

61 голосов
/ 22 марта 2011

Я ценю, что этот пост немного опоздал, но этот фрагмент кода может оказаться полезным.

string path = @"c:\temp";
string NtAccountName = @"MyDomain\MyUserOrGroup";

DirectoryInfo di = new DirectoryInfo(path);
DirectorySecurity acl = di.GetAccessControl(AccessControlSections.All);
AuthorizationRuleCollection rules = acl.GetAccessRules(true, true, typeof(NTAccount));

//Go through the rules returned from the DirectorySecurity
foreach (AuthorizationRule rule in rules)
{
    //If we find one that matches the identity we are looking for
    if (rule.IdentityReference.Value.Equals(NtAccountName,StringComparison.CurrentCultureIgnoreCase))
    {
        var filesystemAccessRule = (FileSystemAccessRule)rule;

        //Cast to a FileSystemAccessRule to check for access rights
        if ((filesystemAccessRule.FileSystemRights & FileSystemRights.WriteData)>0 && filesystemAccessRule.AccessControlType != AccessControlType.Deny)
        {
            Console.WriteLine(string.Format("{0} has write access to {1}", NtAccountName, path));
        }
        else
        {
            Console.WriteLine(string.Format("{0} does not have write access to {1}", NtAccountName, path));
        }
    }
}

Console.ReadLine();

Перетащите это в консольное приложение и посмотрите, делает ли оно то, что вам нужно.

58 голосов
/ 11 сентября 2009

Это совершенно правильный способ проверить доступ к папке в C #. Единственное место, где он может упасть, это если вам нужно вызывать его в узком цикле, где издержки исключения могут быть проблемой.

Были и другие похожие вопросы , заданные ранее.

56 голосов
/ 16 июня 2011
public bool IsDirectoryWritable(string dirPath, bool throwIfFails = false)
{
    try
    {
        using (FileStream fs = File.Create(
            Path.Combine(
                dirPath, 
                Path.GetRandomFileName()
            ), 
            1,
            FileOptions.DeleteOnClose)
        )
        { }
        return true;
    }
    catch
    {
        if (throwIfFails)
            throw;
        else
            return false;
    }
}
19 голосов
/ 24 февраля 2014

Я пробовал большинство из них, но они дают ложные срабатывания, все по той же причине. Недостаточно проверить каталог на наличие разрешений, вы должны убедиться, что зарегистрированный пользователь является членом группы у которого есть это разрешение. Для этого вы получаете удостоверение пользователя и проверяете, является ли он членом группы, которая содержит FileSystemAccessRule IdentityReference. Я проверял это, работает без нареканий ..

    /// <summary>
    /// Test a directory for create file access permissions
    /// </summary>
    /// <param name="DirectoryPath">Full path to directory </param>
    /// <param name="AccessRight">File System right tested</param>
    /// <returns>State [bool]</returns>
    public static bool DirectoryHasPermission(string DirectoryPath, FileSystemRights AccessRight)
    {
        if (string.IsNullOrEmpty(DirectoryPath)) return false;

        try
        {
            AuthorizationRuleCollection rules = Directory.GetAccessControl(DirectoryPath).GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
            WindowsIdentity identity = WindowsIdentity.GetCurrent();

            foreach (FileSystemAccessRule rule in rules)
            {
                if (identity.Groups.Contains(rule.IdentityReference))
                {
                    if ((AccessRight & rule.FileSystemRights) == AccessRight)
                    {
                        if (rule.AccessControlType == AccessControlType.Allow)
                            return true;
                    }
                }
            }
        }
        catch { }
        return false;
    }
13 голосов
/ 22 июня 2012

Например, для всех пользователей (Builtin \ Users) этот метод работает нормально - наслаждайтесь.

public static bool HasFolderWritePermission(string destDir)
{
   if(string.IsNullOrEmpty(destDir) || !Directory.Exists(destDir)) return false;
   try
   {
      DirectorySecurity security = Directory.GetAccessControl(destDir);
      SecurityIdentifier users = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null);
      foreach(AuthorizationRule rule in security.GetAccessRules(true, true, typeof(SecurityIdentifier)))
      {
          if(rule.IdentityReference == users)
          {
             FileSystemAccessRule rights = ((FileSystemAccessRule)rule);
             if(rights.AccessControlType == AccessControlType.Allow)
             {
                    if(rights.FileSystemRights == (rights.FileSystemRights | FileSystemRights.Modify)) return true;
             }
          }
       }
       return false;
    }
    catch
    {
        return false;
    }
}
10 голосов
/ 11 сентября 2009

ИМХО единственный 100% надежный способ проверить, можете ли вы записать в каталог, - это фактически записать его и в конечном итоге перехватить исключения.

8 голосов
/ 19 октября 2012

Попробуйте это:

try
{
    DirectoryInfo di = new DirectoryInfo(path);
    DirectorySecurity acl = di.GetAccessControl();
    AuthorizationRuleCollection rules = acl.GetAccessRules(true, true, typeof(NTAccount));

    WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
    WindowsPrincipal principal = new WindowsPrincipal(currentUser);
    foreach (AuthorizationRule rule in rules)
    {
        FileSystemAccessRule fsAccessRule = rule as FileSystemAccessRule;
        if (fsAccessRule == null)
            continue;

        if ((fsAccessRule.FileSystemRights & FileSystemRights.WriteData) > 0)
        {
            NTAccount ntAccount = rule.IdentityReference as NTAccount;
            if (ntAccount == null)
            {
                continue;
            }

            if (principal.IsInRole(ntAccount.Value))
            {
                Console.WriteLine("Current user is in role of {0}, has write access", ntAccount.Value);
                continue;
            }
            Console.WriteLine("Current user is not in role of {0}, does not have write access", ntAccount.Value);                        
        }
    }
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("does not have write access");
}
6 голосов
/ 11 сентября 2009

Ваш код получает DirectorySecurity для данного каталога и правильно обрабатывает исключение (из-за отсутствия доступа к информации о безопасности). Однако в вашем примере вы на самом деле не запрашиваете возвращенный объект, чтобы увидеть, какой доступ разрешен - и я думаю, что вам нужно добавить это в.

6 голосов
/ 16 апреля 2013

Вот модифицированная версия ответа CsabaS , в которой указаны явные правила запрета доступа. Функция просматривает все FileSystemAccessRules для каталога и проверяет, находится ли текущий пользователь в роли, которая имеет доступ к каталогу. Если такие роли не найдены или пользователь находится в роли с запрещенным доступом, функция возвращает false. Чтобы проверить права на чтение, передайте FileSystemRights.Read функции; для прав записи передайте FileSystemRights.Write. Если вы хотите проверить произвольные права пользователя, а не права текущего, замените currentUser WindowsIdentity на желаемый WindowsIdentity. Я также не советую полагаться на такие функции, чтобы определить, может ли пользователь безопасно использовать каталог. Этот ответ прекрасно объясняет почему.

    public static bool UserHasDirectoryAccessRights(string path, FileSystemRights accessRights)
    {
        var isInRoleWithAccess = false;

        try
        {
            var di = new DirectoryInfo(path);
            var acl = di.GetAccessControl();
            var rules = acl.GetAccessRules(true, true, typeof(NTAccount));

            var currentUser = WindowsIdentity.GetCurrent();
            var principal = new WindowsPrincipal(currentUser);
            foreach (AuthorizationRule rule in rules)
            {
                var fsAccessRule = rule as FileSystemAccessRule;
                if (fsAccessRule == null)
                    continue;

                if ((fsAccessRule.FileSystemRights & accessRights) > 0)
                {
                    var ntAccount = rule.IdentityReference as NTAccount;
                    if (ntAccount == null)
                        continue;

                    if (principal.IsInRole(ntAccount.Value))
                    {
                        if (fsAccessRule.AccessControlType == AccessControlType.Deny)
                            return false;
                        isInRoleWithAccess = true;
                    }
                }
            }
        }
        catch (UnauthorizedAccessException)
        {
            return false;
        }
        return isInRoleWithAccess;
    }
5 голосов
/ 10 июля 2012

Я использовал ту же функцию для проверки наличия файла WriteAccess:

    private static bool HasWriteAccessToFile(string filePath)
    {
        try
        {
            // Attempt to get a list of security permissions from the file. 
            // This will raise an exception if the path is read only or do not have access to view the permissions. 
            File.GetAccessControl(filePath);
            return true;
        }
        catch (UnauthorizedAccessException)
        {
            return false;
        }
    }
...