C#测试用户是否具有文件夹的写入权限

时间:2009-09-11 10:14:55

标签: c# permissions directory

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

我已经实现了以下方法(在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搜索如何测试写访问时,没有出现这样的情况,实际测试Windows中的权限似乎非常复杂。我担心我过度简化了事情,并且这种方法并不健全,尽管它确实有效。

我的方法是否可以测试当前用户是否具有正确的写入权限?

19 个答案:

答案 0 :(得分:60)

我很欣赏这篇帖子的当天晚些时候,但您可能会发现这段代码很有用。

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

将其放入控制台应用程序,看看它是否符合您的要求。

答案 1 :(得分:57)

这是检查C#中文件夹访问权限的完全有效方法。它可能失败的唯一地方是,如果你需要在一个紧凑的循环中调用它,异常的开销可能是一个问题。

以前曾问过其他similar questions

答案 2 :(得分:56)

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

答案 3 :(得分:19)

我尝试了大部分这些,但是他们给出了误报,所有这些都是出于同样的原因。仅仅测试目录的可用权限是不够的,你必须检查登录用户是否是组的成员有这个许可。为此,您将获得用户标识,并检查它是否是包含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;
    }

答案 4 :(得分: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 :(得分:10)

恕我直言,只有100%可靠的方法来测试你是否可以写入目录是实际写入它并最终捕获异常。

答案 6 :(得分:8)

试试这个:

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

答案 7 :(得分:6)

您的代码获取给定目录的DirectorySecurity,并正确处理异常(由于您无权访问安全信息)。但是,在您的示例中,您实际上并不询问返回的对象以查看允许的访问权限 - 我认为您需要将其添加到其中。

答案 8 :(得分:6)

以下是CsabaS's answer的修改版本,它考虑了明确的拒绝访问规则。该函数遍历目录的所有FileSystemAccessRules,并检查当前用户是否具有可访问目录的角色。如果未找到此类角色或用户处于拒绝访问的角色,则该函数返回false。要检查读取权限,请将FileSystemRights.Read传递给该函数;对于写权限,传递FileSystemRights.Write。如果要检查任意用户的权限而不是当前用户的权限,请将currentUser 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;
    }

答案 9 :(得分:5)

我使用相同的函数检查文件是否包含了对象:

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

答案 10 :(得分: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 
}

答案 11 :(得分:2)

以上解决方案很好,但对我而言,我觉得这段代码简单易行。 只需创建一个临时文件。如果创建了文件,则其平均用户具有写访问权。

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

答案 12 :(得分:2)

您的代码中存在潜在的竞争条件 - 如果用户在您检查时有权写入该文件夹,但在用户实际写入该文件夹之前,该权限将被撤销,会发生什么?写入将抛出一个您需要捕获和处理的异常。所以初步检查毫无意义。您也可以只执行编写并处理任何异常。这是适合您情况的标准模式。

答案 13 :(得分:2)

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

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

答案 14 :(得分:1)

只是尝试访问相关文件并不一定足够。测试将以运行程序的用户的权限运行 - 这不一定是您要测试的用户权限。

答案 15 :(得分: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;
        }

希望这有帮助。

答案 16 :(得分: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

}

希望它有所帮助!

答案 17 :(得分:0)

我同意Ash,那应该没问题。或者,如果他们没有访问权限,您可以使用声明性CAS并实际阻止程序首先运行。

我相信某些CAS功能可能不会出现在我所听到的C#4.0中,不确定这可能是一个问题。

答案 18 :(得分:0)

此处大多数答案不检查写访问权限。它只是检查用户/组是否可以“读取权限”(读取文件/目录的ACE列表)。

也无法通过ACE进行迭代并检查其是否与安全标识符匹配,因为用户可以是他可能会获得/失去特权的组的成员。更糟糕的是嵌套组。

我知道这是一个旧线程,但是对于任何现在看的人来说,都有更好的方法。

如果用户具有读取权限特权,则可以使用Authz API来检查有效访问权限。

https://docs.microsoft.com/en-us/windows/win32/secauthz/using-authz-api

https://docs.microsoft.com/en-us/windows/win32/secauthz/checking-access-with-authz-api