如何检查写入目录或文件的权限?

Posted

技术标签:

【中文标题】如何检查写入目录或文件的权限?【英文标题】:How do you check for permissions to write to a directory or file? 【发布时间】:2008-09-24 23:34:03 【问题描述】:

我有一个程序,它使用如下方法将一些数据写入文件。


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


     

运行程序时出现错误:

未处理的异常:System.UnauthorizedAccessException:对路径“mypath”的访问被拒绝。 在 System.IO.__Error.WinIOError(Int32 错误代码,字符串可能全路径) 在 System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, nt32 权限、布尔用户权限、文件共享共享、Int32 缓冲区大小、文件选项 选项,SECURITY_ATTRIBUTES secAttrs,字符串 msgPath,布尔 bFromProxy) 在 System.IO.FileStream..ctor(字符串路径,FileMode 模式,FileAccess 访问 FileShare 共享、Int32 bufferSize、FileOptions 选项、String msgPath、Boolea bFromProxy)

问题:我需要什么代码来捕获它以及如何授予访问权限?

【问题讨论】:

【参考方案1】:

更新:

基于this answer修改了代码,去掉了过时的方法。

您可以使用 Security 命名空间来检查:

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
    


就获得这些权限而言,您将不得不要求用户以某种方式为您执行此操作。如果您可以以编程方式执行此操作,那么我们都会遇到麻烦;)

【讨论】:

这个解决方案不起作用,SecurityManager.IsGranted 返回 true,即使我没有文件的写权限(Win XP SP3) 您是以本地管理员身份运行,还是以没有访问权限的低权限用户身份运行? SecurityManager.IsGranted 已过时。这个答案可能不会永远有效。 @Jetnor - 您正在寻找SecurityManager.IsGranted 方法。它在 4.0 中被弃用,取而代之的是使用 PermissionSets。上面的代码应该没有太大的不同,但不是检查PermissionSet,而是一次只检查一个权限。 @Josh 在你的电脑上试试这个......创建一个新文件夹,(确保它有管理员,完全控制,并且你是管理员组的一部分),然后添加你自己/ Windows 帐户添加到安全列表,然后编辑您的权限并将拒绝放在写入...您的方法为写入返回 True,因为管理员具有写入访问权限,而拒绝优先于您的帐户条目。因此,您的方法对我不起作用...请参阅下面的答案。【参考方案2】:

当您的代码执行以下操作时:

    检查当前用户是否有权做某事。 执行需要在 1 中签入的权利的操作。

您冒着权限在 12 之间发生变化的风险,因为您无法预测系统在运行时还会发生什么。因此,即使您之前检查过权限,您的代码也应该处理引发 UnauthorisedAccessException 的情况。

请注意,SecurityManager 类用于检查 CAS 权限,实际上并不与操作系统检查当前用户是否具有对指定位置的写入权限(通过 ACL 和 ACE)。因此,对于本地运行的应用程序,IsGranted 将始终返回 true。

示例(源自Josh's example):

//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.

尝试根据原始 ACL(所有这些都可以通过 System.Security.AccessControl em> 类)。 Stack Overflow 和更广泛的网络上的其他答案建议尝试执行该操作以了解是否允许权限。 This 帖子总结了实现权限计算所需的内容,应该足以让您停止执行此操作。

【讨论】:

这个理念很好,但并不普遍。例如,我需要显示一个对话框,用户在其中选择要写入的文件夹的路径,并且我想用合理的初始值作为建议填充对话框,如果没有,则创建目标文件夹不存在。出于向后兼容性的原因,默认路径是“C:\”。如果用户不能在那里写,我想回退到 AppData 下的默认值。我没有办法尝试创建一个文件夹,然后再次删除它,只是为了确定文件夹浏览对话框的初始值。【参考方案3】:

它是 MaxOvrdrv 的 Code 的固定版本。

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;

【讨论】:

这真的有效!我猜选择的答案会根据登录用户而不是应用程序检查权限。 这行得通!我检查了C:\Program Files\... 文件夹,但没有以管理员身份运行我的应用程序。 IsWriteable() 在这种情况下返回 false。【参考方案4】:

抱歉,以前的解决方案都没有帮助我。我需要检查双方:SecurityManager 和 SO 权限。我从 Josh 代码和 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!

【讨论】:

【参考方案5】:

由于这没有关闭,我想为任何希望为他们正常工作的人提交一个新条目......使用我在此处找到的内容的合并,以及使用 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;
    

【讨论】:

我注意到两个 (IMO) 可能的改进。 1、检查IsReadable开头的目录(me.Exists)是否存在。 2、在 IsWritable 中,将 IsReadable 检查移到顶部。另请注意,某些情况下允许写入文件但不读取文件,因此有些人希望保持这两种方法“未链接”。 另外,我相信将方法调用之外的枚举组合并使其成为静态将起作用: public static FileSystemRights _ReadRights = FileSystemRights.Read | FileSystemRights.ReadAndExecute | FileSystemRights.ReadAttributes | FileSystemRights.ReadData | FileSystemRights.ReadExtendedAttributes | FileSystemRights.ReadPermissions;然后简化您的测试调用: if (rule.FileSystemRights.HasFlag(_ReadRights) && rule.AccessControlType == AccessControlType.Deny) 嗨@Pedro77 -- 很好奇......你在什么操作系统上运行?我一直在使用它,并且一直在 XP、Vista 和 Win7 上对其进行测试,并且所有 3 都可以完美运行。您使用的是 Windows 8 吗? Win7 x64。以管理员身份登录,未运行的应用是管理员。 @Pedro77 : ***.com/a/31040692/836308 这将解决您的问题。【参考方案6】:

这些都不适合我.. 它们返回为真,即使它们不是。问题是,您必须针对当前进程用户权限测试可用权限,这将测试文件创建权限,只需将 FileSystemRights 子句更改为 'Write' 以测试写入权限..

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

【讨论】:

这是迄今为止最好的答案...但是,您应该修改代码以考虑到 Deny 优先于 allow 使用 2 个布尔值... 它为 C:\\ 返回 true,但是当我尝试在 C:\\ 中创建任何文件时出现异常【参考方案7】:

您可以尝试以下代码块来检查目录是否具有写入权限。

它检查 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                 
           

【讨论】:

它不起作用。它为 C:\\ 返回 true,但是当我尝试在 C:\\ 中创建任何文件时出现异常。【参考方案8】:

哇...这个线程中有很多低级安全代码——其中大部分对我也不起作用——尽管我在这个过程中学到了很多东西。我了解到的一件事是,这些代码中的大部分代码并不适用于寻求每个用户访问权限的应用程序 - 它适用于希望以编程方式更改权限的管理员,正如已经指出的那样,不是 em> 一件好事。作为一名开发人员,我不能使用“简单的方法”——以管理员身份运行——这——我不是运行代码的机器上的人,我的用户也不是——所以,就像这些解决方案一样聪明-- 它们不适合我的情况,也可能不适合大多数普通开发人员。

像大多数这类问题的发帖者一样——我最初也觉得它是“hackey”——我已经决定尝试它是完全可以的,让可能的异常告诉你用户的权利是什么——因为我得到的信息并没有告诉我这些权利到底是什么。下面的代码——做了。

  Private Function CheckUserAccessLevel(folder As String) As Boolean
Try
  Dim newDir As String = String.Format("012",
                                       folder,
                                       If(folder.EndsWith("\"),
                                          "",
                                          "\"),
                                       "LookWhatICanDo")
  Dim lookWhatICanDo = Directory.CreateDirectory(newDir)

  Directory.Delete(newDir)
  Return True

Catch ex As Exception
  Return False
End Try

结束函数

【讨论】:

以上是关于如何检查写入目录或文件的权限?的主要内容,如果未能解决你的问题,请参考以下文章

当“受控文件夹访问”打开时如何检查 .NET 中的目录写入权限

检查 .NET 中的目录和文件写入权限

如何在linux上设置写入但不删除目录的权限?

如何检查用户选择的文件是不是我的沙盒应用程序具有写入权限?

电脑无法正常安装程序出现无法打开要写入的文件

如何授予 PHP 对目录的写入权限?