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

时间:2008-09-24 23:34:04

标签: c# .net

我有一个程序,使用类似下面的方法将一些数据写入文件。


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 errorCode,String maybeFullPath)      在System.IO.FileStream.Init(字符串路径,FileMode模式,FileAccess访问,   nt32 rights,布尔值useRights,FileShare共享,Int32 bufferSize,FileOptions   ptions,SECURITY_ATTRIBUTES secAttrs,String msgPath,Boolean bFromProxy)      在System.IO.FileStream..ctor(字符串路径,FileMode模式,FileAccess访问   FileShare共享,Int32 bufferSize,FileOptions选项,字符串msgPath,Boolea   bFromProxy)

问题:我需要使用哪些代码来获取此信息以及如何授予访问权限?

8 个答案:

答案 0 :(得分:63)

<强>更新

修改了基于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
    }

}

至于获得这些许可,您将不得不要求用户以某种方式为您执行此操作。如果你能以编程方式做到这一点,那么我们都会遇到麻烦;)

答案 1 :(得分:30)

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

  1. 检查当前用户是否有权做某事。
  2. 执行需要在1中检查权利的操作。
  3. 您存在权限在 1 2 之间更改的风险,因为您无法预测在运行时系统上还会发生什么。因此,即使您之前已经检查过权限,您的代码也应该处理抛出 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提供的所有内容)计算文件夹中的有效权限类)。 Stack Overflow和更广泛的网站上的其他答案建议尝试执行操作以了解是否允许权限。 This帖子总结了实施权限计算所需的内容,应足以让您无法执行此操作。

答案 2 :(得分:9)

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

答案 3 :(得分:6)

很抱歉,但以前的解决方案都没有帮助我。我需要检查双方:SecurityManager和SO权限。我已经从Josh代码和iain答案中学到了很多,但我担心我需要使用Rakesh代码(也要感谢他)。只有一个bug:我发现他只检查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!

答案 4 :(得分:4)

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

答案 5 :(得分:3)

这些都不适合我......他们的回归是真实的,即使他们不是。问题是,您必须针对当前进程用户权限测试可用权限,此测试文件创建权限,只需将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;
}

答案 6 :(得分:2)

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

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

答案 7 :(得分:0)

哇......这个帖子中有很多低级别的安全代码 - 其中大部分对我来说都不起作用 - 尽管我在这个过程中学到了很多东西。我学到的一件事是,大多数代码都不适合寻求每个用户访问权限的应用程序 - 管理员希望以编程方式更改权限,正如已经指出的那样,不是

像大多数这类问题的海报一样 - 我最初觉得它也是“hackey” - 我已经决定尝试它是完全没问题,让可能的例外告诉你用户的权利究竟是什么 - 因为我得到的信息并没有告诉我实际上是什么权利。下面的代码 - 确实。

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

  Directory.Delete(newDir)
  Return True

Catch ex As Exception
  Return False
End Try

结束功能