2009-09-11 121 views
154

我需要测试用户是否可以在实际尝试写入文件夹之前写入文件夹。C#测试用户是否有写入文件夹的权限

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

当我googling如何测试写访问没有像这样出现,它似乎很复杂,实际上在Windows中测试权限。我担心我过于简化了一些东西,并且这种方法并不健全,尽管它似乎有效。

我的方法来测试当前用户是否有写权限正常工作?

+12

无法访问**视图**权限真的和不被允许写入的权限相同吗? – deed02392 2013-09-19 15:02:16

回答

51

这是检查C#文件夹访问的完美方法。唯一可能的原因是如果您需要在严格的循环中调用这个例外,那么例外的开销可能是是一个问题。

还有其他similarquestions以前问。

+1

有趣的是,我有另一个标签中打开的其他问题之一,但没有看到有关DirectorySecurity的答案,教我阅读*所有*的答案不只是接受的答案;-) – 2009-09-11 10:45:13

+0

它不会也跌倒时你在Windows中使用长路径? – Alexandru 2015-04-20 18:18:18

+6

这不会告诉你,如果你有写权限,它只会告诉你,如果你可以查询该文件夹的权限或不。你也许可以写但不能查询权限。 – RandomEngy 2015-05-26 00:15:08

7

恕我直言唯一的100%可靠的方法来测试,如果你能写的目录是实际写它,并最终捕获异常。

0

我同意Ash,这应该没问题。或者,您可以使用声明式CAS,并且实际上可以防止程序在无法访问的情况下首先运行。

我相信一些CAS功能可能无法出现在C来自我听说#4.0,不知道这可能是一个问题或没有。

6

你的代码获取DirectorySecurity对于一个给定的目录,并正确处理异常(由于您没有访问安全信息)。然而,你的样品中,你实际上并不询问返回的对象看到的是什么允许访问 - 我认为你需要在添加此

+0

+1 - 我只是遇到了这个问题,当调用GetAccessControl时没有抛出异常,但是当我尝试写入同一个目录时,我得到了未经授权的异常。 – Mayo 2011-01-20 15:49:47

2

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

3

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

这就是我的代码已经做的 – 2009-11-26 16:34:52

54

我明白,这篇文章有点晚,但您可能会发现这段代码有用。

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)) 
    { 
     var filesystemAccessRule = (FileSystemAccessRule)rule; 

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

丢弃到一个控制台应用程序,看看它做你需要什么。

+0

正确的目标!帮助我很多! – smwikipedia 2011-11-30 02:27:40

+0

我在调用'GetAccessControl'时遇到异常,但是我的软件实际上能够写入我正在查看的目录..? – 2012-05-10 13:50:28

+0

@JonCage - 你有什么异常?讽刺的是,首先想到的是安全问题。您的应用运行的帐户是否具有获取ACL信息的权限? – 2012-05-16 20:48:32

42
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; 
    } 
} 
+5

这个答案将会记录所有在尝试写入文件时可能发生的异常,而不仅仅是权限违规。 – 2011-06-17 09:42:42

+0

差不多好!但如何做,而无需创建一个实际的文件..如果一个同名的文件已经存在那里...好试试虽然:) – 2013-05-06 17:12:31

+7

@GY,'字符串tempFileName = Path.GetRandomFileName();',显然 – 2014-02-05 09:37:09

1

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

13

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

我用同样的功能检查,如果文件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; 
     } 
    } 
+0

如果它没有写入但具有读取访问权限,则返回true。 – 2016-01-29 04:59:00

7

试试这个:

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

如果我没有弄错,这很接近但并不完全 - 它忽略了'fsAccessRule.AccessControlType'可能是'AccessControlType.Deny'的事实。 – 2017-06-19 21:23:39

+0

这是在我的Win7开发机器上工作,但在Win10上失败(对于测试人员和我自己的测试机器)。 ssds的修改(见下文)似乎修复它。 – winwaed 2017-10-28 20:07:25

5

这里是CsabaS's answer修改后的版本,占明确拒绝访问规则。该函数遍历目录的所有FileSystemAccessRules,并检查当前用户是否在可访问目录的角色中。如果未找到此类角色或用户处于拒绝访问的角色中,则该函数返回false。要检查读取权限,请将FileSystemRights.Read传递给函数;对于写权限,传递FileSystemRights.Write。如果要检查任意用户的权限而不是当前用户的权限,请将当前用户WindowsIdentity替换为所需的WindowsIdentity。我还建议不要依赖这样的功能来确定用户是否可以安全地使用目录。 This答案完美地解释了原因。

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

Csaba的代码在Windows 10上失败了(但在我的Win7开发机器上很好)。以上似乎解决了这个问题。 – winwaed 2017-10-28 20:06:06

0

我无法按照接受的答案中的建议让GetAccessControl()在Windows 7上抛出异常。

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

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

希望这有助于。

12

我尝试了大多数这些,但他们给出了误报,都出于同样的原因。仅测试目录的可用权限是不够的,您必须检查登录的用户是否是拥有该权限的组。为此,您可以获取用户身份,并检查它是否为包含FileSystemAccessRule IdentityReference的组的成员。我测试了这一点,完美的作品..

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

谢谢John,我也有误报,直到我用你的代码再次检查用户组规则IdentifyReference! – 2017-06-22 19:50:34

+0

这应该被标记为正确的答案。 – 2018-02-15 12:05:06

0

我面临同样的问题:如何验证,如果我能在一个特定的目录的读/写。我结束了简单的解决方案......实际测试它。 这是我简单而有效的解决方案。

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 

} 

希望它有帮助!

0

以上的解决方案都很好,但对我来说,我觉得这个代码简单而且可行。 只需创建一个临时文件。如果该文件已创建,则其平均用户具有写权限。

 public static bool HasWritePermission(string tempfilepath) 
     { 
      try 
      { 
       System.IO.File.Create(tempfilepath + "temp.txt").Close(); 
       System.IO.File.Delete(tempfilepath + "temp.txt"); 
      } 
      catch (System.UnauthorizedAccessException ex) 
      { 

       return false; 
      } 

      return true; 
     } 
+2

不错!但有一点是,该用户可能具有“创建”权限,但不具有“删除”权限,在这种情况下,即使用户_does_具有写入权限,这也会返回false。 – 2018-01-30 10:12:13