Как вы проверяете разрешения на запись в каталог или файл?

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

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 (путь String, режим FileMode, доступ к FileAccess, права nt32, логические useRights, общий ресурс FileShare, Int32 bufferSize, FileOptions ptions, SECURITY_ATTRIBUTES secAttrs , String msgPath, Boolean bFromProxy) в System.IO.FileStream..ctor (путь String, режим FileMode, доступ к файловому файлу FileAhare, параметры Int32 bufferSize, FileOptions, String msgPath, Boolea bFromProxy)

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

ОБНОВИТЬ:

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

Вы можете использовать пространство имен 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 } } 

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

Когда ваш код делает следующее:

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

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

Обратите внимание, что class 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 (которые доступны всем classам System.Security.AccessControl ). Другие ответы на Stack Overflow и более широкую сеть рекомендуют попытаться выполнить действие, чтобы узнать, разрешено ли разрешение. В этом сообщении суммируется то, что требуется для выполнения расчета разрешений, и должно быть достаточно, чтобы не дать вам этого сделать.

Его фиксированная версия кода MaxOvrdrv.

 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; } 

Извините, но ни одно из предыдущих решений не помогло мне. Мне нужно проверить обе стороны: разрешения SecurityManager и SO. Я многому научился с кодом Josh и с ответом iain, но, боюсь, мне нужно использовать код Rakesh (также благодаря ему). Только одна ошибка: я обнаружил, что он проверяет только разрешения Allow, а не разрешения Deny. Поэтому мое предложение:

  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(); 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! 

Поскольку это не закрыто, я хотел бы представить новую запись для тех, кто ищет что-то подходящее для них … используя объединение того, что я нашел здесь, а также используя 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; } 

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

 ///  /// Test a directory for create file access permissions ///  /// Full directory path /// State [bool] 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; } 

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

Он проверяет 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 } 

Вау … в этом streamе есть много низкоуровневого кода безопасности, и большинство из них не работало для меня, хотя я многому научился в этом процессе. Одна вещь, которую я узнал, состоит в том, что большая часть этого кода не предназначена для приложений, требующих права доступа для каждого пользователя, – это для администраторов, желающих программно изменить права, которые, как уже отмечалось, не очень хороши. Как разработчик, я не могу использовать «простой выход» – запустив его как «Администратор», который – я не один на машине, на которой работает код, и не на моих пользователей, – настолько умным, насколько эти решения – они не для моей ситуации и, вероятно, не для большинства разработчиков ранга и файлов.

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

  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 

Конечная функция

  • Переопределение общедоступных виртуальных функций с частными функциями в C ++
  • Как я могу написать единичный тест, чтобы определить, можно ли собирать мусор?
  • Начальная C ++ неинициализированная локальная переменная
  • Простое доказательство того, что GUID не уникален
  • Как динамически создавать элементы управления ASP.net в динамически созданных элементах управления ASP.net
  • GNU C ++ как проверить, когда -std = c ++ 0x действует?
  • Каково использование метода расширения Enumerable.Zip в Linq?
  • программно добавлять столбцы и строки в WPF Datagrid
  • C # найти максимальное значение и индекс массива
  • Как читать из stdin с помощью fgets ()?
  • Как заставить курсор переходить к курсору ожидания?
  • Давайте будем гением компьютера.