C#testing用户是否有写入权限的文件夹

我需要testing用户是否可以在实际尝试之前写入文件夹。

我已经实现了以下方法(在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; } } 

当我在Google上search如何testing写入权限时,没有出现这种情况,而且在Windows中实际testing权限显得非常复杂。 我担心我过于简化了,而且这种方法并不健壮,尽pipe它似乎有效。

我的方法来testing,如果当前用户有写访问工作正常吗?

这是一个非常有效的方式来检查在C#中的文件夹访问。 唯一可能的地方就是如果你需要在一个严格的循环中调用这个例外,这个例外的开销可能会成为一个问题。

之前还有其他类似的 问题 。

我明白,这篇文章在这一天已经有点晚了,但是你可能会发现这个代码有用。

 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)) { //Cast to a FileSystemAccessRule to check for access rights if ((((FileSystemAccessRule)rule).FileSystemRights & FileSystemRights.WriteData)>0) { 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(); 

将其放入控制台应用程序中,看看它是否满足您的需求。

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

例如,对于所有用户(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; } } 

我尝试了其中的大多数,但是他们给出了误报,都是出于同样的原因。仅仅testing一个可用权限的目录是不够的,你必须检查login的用户是否具有该权限允许。 要做到这一点,你得到的用户身份,并检查它是否是包含FileSystemAccessRule IdentityReference组的成员。 我已经testing了这个,完美的工作。

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

恕我直言,只有100%可靠的方法来testing,如果你可以写入目录是实际写入它,并最终捕获exception。

尝试这个:

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

您的代码获取给定目录的DirectorySecurity ,并正确处理exception(由于您无法访问安全信息)。 然而,在你的示例中,你并没有实际询问返回的对象,看看允许什么访问 – 我想你需要添加这个。

我用相同的函数检查文件hasWriteAccess:

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

这里是CsabaS的答案的修改版本,它解释了明确的拒绝访问规则。 该函数遍历所有FileSystemAccessRules的目录,并检查当前用户是否在可以访问目录的angular色中。 如果没有find这样的angular色或者用户处于被拒绝访问的angular色中,则该函数返回false。 要检查读取权限,请将FileSystemRights.Read传递给函数; 为写权限,通过FileSystemRights.Write。 如果要检查任意用户的权限而不是当前用户的权限,请将当前用户WindowsIdentityreplace为所需的WindowsIdentity。 我也build议不要依赖这样的function来确定用户是否可以安全地使用目录。 这个答案完全解释了为什么

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

您可以尝试下面的代码块来检查目录是否具有写访问权限。 它检查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 } 

您的代码中存在潜在的竞争条件 – 如果用户在检查时有权写入文件夹,但在用户实际写入文件夹之前,此权限被撤回,会发生什么情况? 写将会抛出一个exception,你将需要赶上和处理。 所以最初的检查是毫无意义的。 你可能只需要写和处理任何exception。 这是你的情况的标准模式。

http://www.codeproject.com/KB/files/UserFileAccessRights.aspx

非常有用的类,检查消息中的改进版本。

只是试图访问有问题的文件是不够的。 testing将以运行程序的用户的权限运行 – 这不一定是您要testing的用户权限。

我无法按照接受的答案中的build议让GetAccessControl()在Windows 7上引发exception。

我结束了使用sdds的答案变化:

  try { bool writeable = false; WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent()); DirectorySecurity security = Directory.GetAccessControl(pstrPath); AuthorizationRuleCollection authRules = security.GetAccessRules(true, true, typeof(SecurityIdentifier)); foreach (FileSystemAccessRule accessRule in authRules) { if (principal.IsInRole(accessRule.IdentityReference as SecurityIdentifier)) { if ((FileSystemRights.WriteData & accessRule.FileSystemRights) == FileSystemRights.WriteData) { if (accessRule.AccessControlType == AccessControlType.Allow) { writeable = true; } else if (accessRule.AccessControlType == AccessControlType.Deny) { //Deny usually overrides any Allow return false; } } } } return writeable; } catch (UnauthorizedAccessException) { return false; } 

希望这可以帮助。

我同意阿什,那应该没问题。 或者,您可以使用声明性的CAS,并实际上阻止程序在没有访问权限的情况下首先运行。

我相信一些CASfunction可能不会出现在我听到的C#4.0中,不知道这是否是一个问题。

我面临同样的问题:如何validation我是否可以在特定的目录中读/写。 我结束了简单的解决scheme…实际testing它。 这是我简单但有效的解决scheme。

  class Program { /// <summary> /// Tests if can read files and if any are present /// </summary> /// <param name="dirPath"></param> /// <returns></returns> private genericResponse check_canRead(string dirPath) { try { IEnumerable<string> files = Directory.EnumerateFiles(dirPath); if (files.Count().Equals(0)) return new genericResponse() { status = true, idMsg = genericResponseType.NothingToRead }; return new genericResponse() { status = true, idMsg = genericResponseType.OK }; } catch (DirectoryNotFoundException ex) { return new genericResponse() { status = false, idMsg = genericResponseType.ItemNotFound }; } catch (UnauthorizedAccessException ex) { return new genericResponse() { status = false, idMsg = genericResponseType.CannotRead }; } } /// <summary> /// Tests if can wirte both files or Directory /// </summary> /// <param name="dirPath"></param> /// <returns></returns> private genericResponse check_canWrite(string dirPath) { try { string testDir = "__TESTDIR__"; Directory.CreateDirectory(string.Join("/", dirPath, testDir)); Directory.Delete(string.Join("/", dirPath, testDir)); string testFile = "__TESTFILE__.txt"; try { TextWriter tw = new StreamWriter(string.Join("/", dirPath, testFile), false); tw.WriteLine(testFile); tw.Close(); File.Delete(string.Join("/", dirPath, testFile)); return new genericResponse() { status = true, idMsg = genericResponseType.OK }; } catch (UnauthorizedAccessException ex) { return new genericResponse() { status = false, idMsg = genericResponseType.CannotWriteFile }; } } catch (UnauthorizedAccessException ex) { return new genericResponse() { status = false, idMsg = genericResponseType.CannotWriteDir }; } } } public class genericResponse { public bool status { get; set; } public genericResponseType idMsg { get; set; } public string msg { get; set; } } public enum genericResponseType { NothingToRead = 1, OK = 0, CannotRead = -1, CannotWriteDir = -2, CannotWriteFile = -3, ItemNotFound = -4 } 

希望能帮助到你 !