Проверка разрешений на запись в каталог и файл in.NET
в моем приложении .NET 2.0 мне нужно проверить, существуют ли достаточные разрешения для создания и записи файлов в каталог. С этой целью у меня есть следующая функция, которая пытается создать файл и записать в него один байт, удаляя себя после этого, чтобы проверить, что разрешения существуют.
Я решил, что лучший способ проверить, чтобы на самом деле попробовать и сделать это, ловя любые исключения, которые происходят. Я не особенно доволен общим исключением catch, хотя, так что есть лучше или, возможно, более приемлемый способ сделать это?
private const string TEMP_FILE = "tempFile.tmp";
/// <summary>
/// Checks the ability to create and write to a file in the supplied directory.
/// </summary>
/// <param name="directory">String representing the directory path to check.</param>
/// <returns>True if successful; otherwise false.</returns>
private static bool CheckDirectoryAccess(string directory)
{
bool success = false;
string fullPath = directory + TEMP_FILE;
if (Directory.Exists(directory))
{
try
{
using (FileStream fs = new FileStream(fullPath, FileMode.CreateNew,
FileAccess.Write))
{
fs.WriteByte(0xff);
}
if (File.Exists(fullPath))
{
File.Delete(fullPath);
success = true;
}
}
catch (Exception)
{
success = false;
}
}
8 ответов:
ответы Ричард и Джейсон вроде в правильном направлении. Однако то, что вы должны делать это вычисление эффективных разрешений для идентификации пользователя, выполняющего код. Ни один из приведенных выше примеров правильно не учитывает членство в группе, например.
Я почти уверен Кейт Браун был какой-то код, чтобы сделать это в его Вики версия (в автономном режиме в это время) из интернет .Net-разработчиков Руководство по безопасности Windows. Это также обсуждается в разумных деталях в его Программирование Безопасности Windows книги.
вычисление эффективных разрешений не для слабонервных, и ваш код, чтобы попытаться создать файл и поймать исключение безопасности, вероятно, является путем наименьшего сопротивления.
Directory.GetAcessControl(path)делает то, что вы просите.public static bool HasWritePermissionOnDir(string path) { var writeAllow = false; var writeDeny = false; var accessControlList = Directory.GetAccessControl(path); if (accessControlList == null) return false; var accessRules = accessControlList.GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier)); if (accessRules ==null) return false; foreach (FileSystemAccessRule rule in accessRules) { if ((FileSystemRights.Write & rule.FileSystemRights) != FileSystemRights.Write) continue; if (rule.AccessControlType == AccessControlType.Allow) writeAllow = true; else if (rule.AccessControlType == AccessControlType.Deny) writeDeny = true; } return writeAllow && !writeDeny; }
(FileSystemRights.Write & rights) == FileSystemRights.Writeиспользует что-то под названием "флаги" кстати, который, если вы не знаете, что это такое, вы должны действительно прочитать :)
Denyберет верх надAllow. Локальные правила имеют приоритет над унаследованными правилами. Я видел много решений (включая некоторые ответы, показанные здесь), но ни один из них не учитывает, являются ли правила унаследовала или нет. Поэтому я предлагаю следующий подход, который рассматривает наследование правил (аккуратно завернутое в класс):public class CurrentUserSecurity { WindowsIdentity _currentUser; WindowsPrincipal _currentPrincipal; public CurrentUserSecurity() { _currentUser = WindowsIdentity.GetCurrent(); _currentPrincipal = new WindowsPrincipal(WindowsIdentity.GetCurrent()); } public bool HasAccess(DirectoryInfo directory, FileSystemRights right) { // Get the collection of authorization rules that apply to the directory. AuthorizationRuleCollection acl = directory.GetAccessControl() .GetAccessRules(true, true, typeof(SecurityIdentifier)); return HasFileOrDirectoryAccess(right, acl); } public bool HasAccess(FileInfo file, FileSystemRights right) { // Get the collection of authorization rules that apply to the file. AuthorizationRuleCollection acl = file.GetAccessControl() .GetAccessRules(true, true, typeof(SecurityIdentifier)); return HasFileOrDirectoryAccess(right, acl); } private bool HasFileOrDirectoryAccess(FileSystemRights right, AuthorizationRuleCollection acl) { bool allow = false; bool inheritedAllow = false; bool inheritedDeny = false; for (int i = 0; i < acl.Count; i++) { var currentRule = (FileSystemAccessRule)acl[i]; // If the current rule applies to the current user. if (_currentUser.User.Equals(currentRule.IdentityReference) || _currentPrincipal.IsInRole( (SecurityIdentifier)currentRule.IdentityReference)) { if (currentRule.AccessControlType.Equals(AccessControlType.Deny)) { if ((currentRule.FileSystemRights & right) == right) { if (currentRule.IsInherited) { inheritedDeny = true; } else { // Non inherited "deny" takes overall precedence. return false; } } } else if (currentRule.AccessControlType .Equals(AccessControlType.Allow)) { if ((currentRule.FileSystemRights & right) == right) { if (currentRule.IsInherited) { inheritedAllow = true; } else { allow = true; } } } } } if (allow) { // Non inherited "allow" takes precedence over inherited rules. return true; } return inheritedAllow && !inheritedDeny; } }тем не менее, я сделал опыт, что это не всегда работает на удаленных компьютерах, как вы не всегда будете иметь право на запрос прав доступа к файлам нет. Решение в этом случае-попробовать; возможно, даже просто попытавшись создать временный файл, если вам нужно знать право доступа перед работой с "реальными" файлами.
принятый ответ Kev на этот вопрос фактически не дает никакого кода, он просто указывает на другие ресурсы, к которым у меня нет доступа. Итак, вот моя лучшая попытка в этой функции. Он фактически проверяет, что разрешение, на которое он смотрит, является разрешением "запись" и что текущий пользователь принадлежит к соответствующей группе.
это может быть не полным в отношении сетевых путей или что-то еще, но это достаточно хорошо для моей цели, проверка локальных файлов конфигурации под "Программные файлы" для удобства записи:
using System.Security.Principal; using System.Security.AccessControl; private static bool HasWritePermission(string FilePath) { try { FileSystemSecurity security; if (File.Exists(FilePath)) { security = File.GetAccessControl(FilePath); } else { security = Directory.GetAccessControl(Path.GetDirectoryName(FilePath)); } var rules = security.GetAccessRules(true, true, typeof(NTAccount)); var currentuser = new WindowsPrincipal(WindowsIdentity.GetCurrent()); bool result = false; foreach (FileSystemAccessRule rule in rules) { if (0 == (rule.FileSystemRights & (FileSystemRights.WriteData | FileSystemRights.Write))) { continue; } if (rule.IdentityReference.Value.StartsWith("S-1-")) { var sid = new SecurityIdentifier(rule.IdentityReference.Value); if (!currentuser.IsInRole(sid)) { continue; } } else { if (!currentuser.IsInRole(rule.IdentityReference.Value)) { continue; } } if (rule.AccessControlType == AccessControlType.Deny) return false; if (rule.AccessControlType == AccessControlType.Allow) result = true; } return result; } catch { return false; } }
IMO, вам нужно работать с такими каталогами, как обычно, но вместо проверки разрешений перед использованием, обеспечить правильный способ обработки UnauthorizedAccessException и реагировать соответствующим образом. Этот метод проще и менее подвержен ошибкам.
попробуйте работать с этим фрагментом C#, который я только что создал:
using System; using System.IO; using System.Security.AccessControl; using System.Security.Principal; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string directory = @"C:\downloads"; DirectoryInfo di = new DirectoryInfo(directory); DirectorySecurity ds = di.GetAccessControl(); foreach (AccessRule rule in ds.GetAccessRules(true, true, typeof(NTAccount))) { Console.WriteLine("Identity = {0}; Access = {1}", rule.IdentityReference.Value, rule.AccessControlType); } } } }и вот!--5--> ссылка вы также можете посмотреть. Мой код может дать вам представление о том, как вы можете проверить разрешения, прежде чем пытаться писать в каталог.
по этой ссылке: http://www.authorcode.com/how-to-check-file-permission-to-write-in-c/
проще использовать существующий класс SecurityManager
string FileLocation = @"C:\test.txt"; FileIOPermission writePermission = new FileIOPermission(FileIOPermissionAccess.Write, FileLocation); if (SecurityManager.IsGranted(writePermission)) { // you have permission } else { // permission is required! }но, похоже, он устарел, вместо этого предлагается использовать PermissionSet.
[Obsolete("IsGranted is obsolete and will be removed in a future release of the .NET Framework. Please use the PermissionSet property of either AppDomain or Assembly instead.")]
private static void GrantAccess(string file) { bool exists = System.IO.Directory.Exists(file); if (!exists) { DirectoryInfo di = System.IO.Directory.CreateDirectory(file); Console.WriteLine("The Folder is created Sucessfully"); } else { Console.WriteLine("The Folder already exists"); } DirectoryInfo dInfo = new DirectoryInfo(file); DirectorySecurity dSecurity = dInfo.GetAccessControl(); dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow)); dInfo.SetAccessControl(dSecurity); }
Comments