Как проверить наличие разрешений на запись в каталог или файл?
Я получил программу, которая записывает некоторые данные в файл с помощью метода, как показано ниже.
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);
}
}
при запуске программы я получаю сообщение об ошибке:
Необработанное Исключение: Система.UnauthorizedAccessException: доступ к пути 'mypath' запрещен. в системе.ИО.__Ошибка.WinIOError(типа int32 код ошибки, строку maybeFullPath) в системе.ИО.Типа FileStream.Метод init(string путь, режим filemode необходимо флагами fileaccess доступ, права nt32, логические права пользователя, общий файловый ресурс, Int32 bufferSize, FileOptions ptions, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) в системе.ИО.Хранилище FileStream..чтор(string путь, режим filemode необходимо открыть флагами fileaccess Общий файловый ресурс, Int32 bufferSize, параметры FileOptions, строка msgPath, Boolea bFromProxy)
вопрос: Какой код мне нужен, чтобы поймать это и как я могу предоставить доступ?
8 ответов:
обновление:
изменен код на основе ответ чтобы избавиться от устаревших методов.
вы можете использовать пространство имен, чтобы проверить это:
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.
вы рискуете, что разрешения меняются между 1 и 2 потому что вы не можете предсказать, что еще будет происходит в системе во время выполнения. Поэтому ваш код должен обрабатывать ситуацию, когда UnauthorisedAccessException бросается, даже если вы уже проверили разрешения.
отметим, что SecurityManager класс используется для проверки разрешений CAS и фактически не проверяет с ОС, имеет ли текущий пользователь доступ на запись в указанное место (через ACL и ACEs). Как таковой,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. }
Это сложно и не рекомендуется чтобы попытаться программно вычислить эффективные разрешения из папки на основе необработанных списков управления доступом (которые все доступны через
его фиксированная версия 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 и так разрешения. Я многому научился с кодом Джоша и с ответом 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<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!
поскольку это не закрыто, я хотел бы представить новую запись для тех, кто хочет, чтобы что-то работало правильно для них... используя объединение того, что я нашел здесь, а также используя 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; }
ни один из них не работал для меня.. они возвращаются как true, даже если это не так. проблема в том, что вам нужно проверить доступное разрешение на текущие права пользователя процесса, это проверяет права на создание файлов, просто измените предложение 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; }
вы можете попробовать следующие блок кода, чтобы проверить, если каталог имеет доступ на запись.
Он проверяет 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 }
Вау...в этом потоке есть много низкоуровневого кода безопасности , большинство из которых также не работает для меня, хотя я многому научился в этом процессе. Одна вещь, которую я узнал, заключается в том, что большая часть этого кода не предназначена для приложений, ищущих права доступа для каждого пользователя-это для администраторов, желающих изменить права программно, что, как было указано,не хорошая вещь. Как разработчик, я не могу использовать "простой выход" -- Запуск от имени администратора -- что - я не один на машине, которая запускает код, и мои пользователи-так что, как бы умны ни были эти решения - они не для моей ситуации, и, вероятно, не для большинства рядовых разработчиков.
Как и большинство плакатов этого типа вопроса - я изначально чувствовал, что это тоже "хакер" - с тех пор я решил, что это совершенно нормально, чтобы попробовать его, и пусть возможное исключение скажет вам точно, какие права пользователя-потому что информация, которую я получил, не сказала мне какие права на самом деле были. Код ниже -- сделал.
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
Конец Функции