Как вы проверяете разрешения на запись в каталог или файл? - PullRequest
57 голосов
/ 25 сентября 2008

Я получил программу, которая записывает некоторые данные в файл, используя метод, подобный приведенному ниже.


public void ExportToFile(string filename)
{
     using(FileStream fstream = new FileStream(filename,FileMode.Create))
     using (TextWriter writer = new StreamWriter(fstream))
     {
         // try catch block for write permissions 
         writer.WriteLine(text);


     }
}

При запуске программы выдается ошибка:

Необработанное исключение: System.UnauthorizedAccessException: доступ к пути «mypath» запрещен. в System.IO .__ Error.WinIOError (Int32 errorCode, String MaybeFullPath) в System.IO.FileStream.Init (путь строки, режим FileMode, доступ к FileAccess, права nt32, логические права на использование, общий доступ к FileShare, размер буфера Int32, FileOptions ptions, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) в System.IO.FileStream..ctor (путь строки, режим FileMode, доступ к FileAccess Общий доступ к FileShare, размер буфера Int32, параметры FileOptions, строка msgPath, Boolea bFromProxy)

Вопрос: Какой код мне нужен, чтобы поймать это и как мне предоставить доступ?

Ответы [ 8 ]

63 голосов
/ 25 сентября 2008

UPDATE:

Изменен код на основе этого ответа , чтобы избавиться от устаревших методов.

Вы можете использовать пространство имен Security для проверки этого:

public void ExportToFile(string filename)
{
    var permissionSet = new PermissionSet(PermissionState.None);    
    var writePermission = new FileIOPermission(FileIOPermissionAccess.Write, filename);
    permissionSet.AddPermission(writePermission);

    if (permissionSet.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet))
    {
        using (FileStream fstream = new FileStream(filename, FileMode.Create))
        using (TextWriter writer = new StreamWriter(fstream))
        {
            // try catch block for write permissions 
            writer.WriteLine("sometext");


        }
    }
    else
    {
        //perform some recovery action here
    }

}

Что касается получения такого разрешения, вам придется попросить пользователя как-нибудь сделать это за вас. Если бы вы могли сделать это программным путем, то у всех нас были бы проблемы;)

30 голосов
/ 20 января 2009

Когда ваш код выполняет следующие действия:

  1. Проверяет, имеет ли текущий пользователь разрешение на что-либо.
  2. Выполняет действие, для которого требуются права, отмеченные в 1.

Вы рискуете изменить разрешения между 1 и 2 , потому что вы не можете предсказать, что еще будет происходить в системе во время выполнения. Следовательно, ваш код должен обрабатывать ситуацию, в которой выдается UnauthorisedAccessException , даже если вы ранее проверили разрешения.

Обратите внимание, что класс SecurityManager используется для проверки разрешений CAS и фактически не проверяет с ОС, имеет ли текущий пользователь доступ на запись в указанное местоположение (через ACL и ACE). Таким образом, IsGranted всегда будет возвращать true для локально работающих приложений.

Пример (полученный из Пример Джоша ):

//1. Provide early notification that the user does not have permission to write.
FileIOPermission writePermission = new FileIOPermission(FileIOPermissionAccess.Write, filename);
if(!SecurityManager.IsGranted(writePermission))
{
    //No permission. 
    //Either throw an exception so this can be handled by a calling function
    //or inform the user that they do not have permission to write to the folder and return.
}

//2. Attempt the action but handle permission changes.
try
{
    using (FileStream fstream = new FileStream(filename, FileMode.Create))
    using (TextWriter writer = new StreamWriter(fstream))
    {
        writer.WriteLine("sometext");
    }
}
catch (UnauthorizedAccessException ex)
{
    //No permission. 
    //Either throw an exception so this can be handled by a calling function
    //or inform the user that they do not have permission to write to the folder and return.
}

Это сложно и не рекомендуется пытаться программно рассчитать эффективные разрешения для папки на основе необработанных ACL-списков (которые доступны через System.Security.AccessControl классы). Другие ответы о переполнении стека и более широкой сети рекомендуют попытаться выполнить действие, чтобы узнать, разрешено ли разрешение. В этом посте подводятся итоги того, что требуется для реализации расчета разрешений, и этого должно быть достаточно, чтобы отговорить вас от этого.

9 голосов
/ 25 июня 2015

Это исправленная версия MaxOvrdrv's Code .

public static bool IsReadable(this DirectoryInfo di)
{
    AuthorizationRuleCollection rules;
    WindowsIdentity identity;
    try
    {
        rules = di.GetAccessControl().GetAccessRules(true, true, typeof(SecurityIdentifier));
        identity = WindowsIdentity.GetCurrent();
    }
    catch (UnauthorizedAccessException uae)
    {
        Debug.WriteLine(uae.ToString());
        return false;
    }

    bool isAllow = false;
    string userSID = identity.User.Value;

    foreach (FileSystemAccessRule rule in rules)
    {
        if (rule.IdentityReference.ToString() == userSID || identity.Groups.Contains(rule.IdentityReference))
        {
            if ((rule.FileSystemRights.HasFlag(FileSystemRights.Read) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.ReadAttributes) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.ReadData)) && rule.AccessControlType == AccessControlType.Deny)
                return false;
            else if ((rule.FileSystemRights.HasFlag(FileSystemRights.Read) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.ReadAttributes) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.ReadData)) && rule.AccessControlType == AccessControlType.Allow)
                isAllow = true;

        }
    }
    return isAllow;
}

public static bool IsWriteable(this DirectoryInfo me)
{
    AuthorizationRuleCollection rules;
    WindowsIdentity identity;
    try
    {
        rules = me.GetAccessControl().GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
        identity = WindowsIdentity.GetCurrent();
    }
    catch (UnauthorizedAccessException uae)
    {
        Debug.WriteLine(uae.ToString());
        return false;
    }

    bool isAllow = false;
    string userSID = identity.User.Value;

    foreach (FileSystemAccessRule rule in rules)
    {
        if (rule.IdentityReference.ToString() == userSID || identity.Groups.Contains(rule.IdentityReference))
        {
            if ((rule.FileSystemRights.HasFlag(FileSystemRights.Write) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.WriteAttributes) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.WriteData) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.CreateDirectories) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.CreateFiles)) && rule.AccessControlType == AccessControlType.Deny)
                return false;
            else if ((rule.FileSystemRights.HasFlag(FileSystemRights.Write) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.WriteAttributes) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.WriteData) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.CreateDirectories) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.CreateFiles)) && rule.AccessControlType == AccessControlType.Allow)
                isAllow = true;

        }
    }
    return isAllow;
}
6 голосов
/ 06 августа 2010

Извините, но ни одно из предыдущих решений не помогло мне. Мне нужно проверить обе стороны: SecurityManager и SO разрешения. Я многому научился с кодом Джоша и с iain ответом, но боюсь, что мне нужно использовать код Ракеша (также благодаря ему). Только одна ошибка: я обнаружил, что он проверяет только разрешения «Разрешить», а не «Запретить». Итак, мое предложение:

        string folder;
        AuthorizationRuleCollection rules;
        try {
            rules = Directory.GetAccessControl(folder)
                .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
        } catch(Exception ex) { //Posible UnauthorizedAccessException
            throw new Exception("No permission", ex);
        }

        var rulesCast = rules.Cast<FileSystemAccessRule>();
        if(rulesCast.Any(rule => rule.AccessControlType == AccessControlType.Deny)
            || !rulesCast.Any(rule => rule.AccessControlType == AccessControlType.Allow))
            throw new Exception("No permission");

        //Here I have permission, ole!
4 голосов
/ 15 августа 2014

Поскольку это не закрыто, я хотел бы представить новую запись для всех, кто хочет, чтобы что-то для них работало должным образом ... используя объединение того, что я нашел здесь, а также используя DirectoryServices для отладки самого кода и найти правильный код для использования, вот что я нашел, что работает для меня в любой ситуации ... обратите внимание, что мое решение расширяет объект DirectoryInfo ...:

    public static bool IsReadable(this DirectoryInfo me)
    {

        AuthorizationRuleCollection rules;
        WindowsIdentity identity;
        try
        {
            rules = me.GetAccessControl().GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
            identity = WindowsIdentity.GetCurrent();
        }
        catch (Exception ex)
        { //Posible UnauthorizedAccessException
            return false;
        }

        bool isAllow=false;
        string userSID = identity.User.Value;

        foreach (FileSystemAccessRule rule in rules)
        {
            if (rule.IdentityReference.ToString() == userSID || identity.Groups.Contains(rule.IdentityReference))
            {
                if ((rule.FileSystemRights.HasFlag(FileSystemRights.Read) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadAndExecute) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadData) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadExtendedAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadPermissions)) && rule.AccessControlType == AccessControlType.Deny)
                    return false;
                else if ((rule.FileSystemRights.HasFlag(FileSystemRights.Read) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadAndExecute) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadData) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadExtendedAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadPermissions)) && rule.AccessControlType == AccessControlType.Allow)
                    isAllow = true;
            }
        }

        return isAllow;
    }

    public static bool IsWriteable(this DirectoryInfo me)
    {
        AuthorizationRuleCollection rules;
        WindowsIdentity identity;
        try
        {
            rules = me.GetAccessControl().GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
            identity = WindowsIdentity.GetCurrent();
        }
        catch (Exception ex)
        { //Posible UnauthorizedAccessException
            return false;
        }

        bool isAllow = false;
        string userSID = identity.User.Value;

        foreach (FileSystemAccessRule rule in rules)
        {
            if (rule.IdentityReference.ToString() == userSID || identity.Groups.Contains(rule.IdentityReference))
            {
                if ((rule.FileSystemRights.HasFlag(FileSystemRights.Write) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteData) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteExtendedAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.CreateDirectories) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.CreateFiles)) && rule.AccessControlType == AccessControlType.Deny)
                    return false;
                else if ((rule.FileSystemRights.HasFlag(FileSystemRights.Write) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteData) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteExtendedAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.CreateDirectories) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.CreateFiles)) && rule.AccessControlType == AccessControlType.Allow)
                    isAllow = true;
            }
        }

        return me.IsReadable() && isAllow;
    }
3 голосов
/ 23 февраля 2014

Ничто из этого не сработало для меня ... они возвращаются как истина, даже если это не так. Проблема в том, что вы должны проверить доступное разрешение на соответствие текущим правам пользователя процесса, это тестирует права на создание файла, просто измените предложение FileSystemRights на «Запись», чтобы проверить доступ на запись ..

/// <summary>
/// Test a directory for create file access permissions
/// </summary>
/// <param name="DirectoryPath">Full directory path</param>
/// <returns>State [bool]</returns>
public static bool DirectoryCanCreate(string DirectoryPath)
{
    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 ((FileSystemRights.CreateFiles & rule.FileSystemRights) == FileSystemRights.CreateFiles)
                {
                    if (rule.AccessControlType == AccessControlType.Allow)
                        return true;
                }
            }
        }
    }
    catch {}
    return false;
}
2 голосов
/ 26 ноября 2009

Вы можете попробовать следующий блок кода, чтобы проверить, имеет ли каталог доступ для записи.

Проверяет FileSystemAccessRule.

           string directoryPath = "C:\\XYZ"; //folderBrowserDialog.SelectedPath;
           bool isWriteAccess = false;
           try
           {
              AuthorizationRuleCollection collection = Directory.GetAccessControl(directoryPath).GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
              foreach (FileSystemAccessRule rule in collection)
              {
                 if (rule.AccessControlType == AccessControlType.Allow)
                 {
                    isWriteAccess = true;
                    break;
                 }
              }
           }
           catch (UnauthorizedAccessException ex)
           {
              isWriteAccess = false;
           }
           catch (Exception ex)
           {
              isWriteAccess = false;
           }
           if (!isWriteAccess)
           {
             //handle notifications                 
           }
0 голосов
/ 27 сентября 2017

Ух ты ... в этой ветке много низкоуровневого кода безопасности - большая часть которого у меня тоже не сработала - хотя я многому научился в процессе. Одна вещь, которую я узнал, заключается в том, что большая часть этого кода не предназначена для приложений, которые ищут права доступа для каждого пользователя, - для администраторов, желающих программно изменять права, что, как было отмечено, составляет , а не * 1002. * хорошая вещь. Как разработчик, я не могу использовать «легкий выход» - работая от имени администратора, - который - я не один на машине, на которой выполняется код, и не мои пользователи, - настолько же, насколько умны эти решения. - они не для моей ситуации и, вероятно, не для большинства рядовых разработчиков.

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

  Private Function CheckUserAccessLevel(folder As String) As Boolean
Try
  Dim newDir As String = String.Format("{0}{1}{2}",
                                       folder,
                                       If(folder.EndsWith("\"),
                                          "",
                                          "\"),
                                       "LookWhatICanDo")
  Dim lookWhatICanDo = Directory.CreateDirectory(newDir)

  Directory.Delete(newDir)
  Return True

Catch ex As Exception
  Return False
End Try

Функция завершения

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...