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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/130617/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 14:54:37  来源:igfitidea点击:

How do you check for permissions to write to a directory or file?

提问by 18hrs

I got a program that writes some data to a file using a method like the one below.

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


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


     }
}

When running the program I get an error:

运行程序时出现错误:

Unhandled Exception: System.UnauthorizedAccessException: Access to the path 'mypath' is denied. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, nt32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions ptions, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolea bFromProxy)

未处理的异常:System.UnauthorizedAccessException:对路径“mypath”的访问被拒绝。在 System.IO.__Error.WinIOError(Int32 errorCode, String MaybeFullPath) 在 System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, nt32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions ptions, SECURITY_ATTRIBUTES secAttrs , String msgPath, Boolean bFromProxy) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolea bFromProxy)

Question: What code do I need to catch this and how do I grant the access?

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

采纳答案by Josh

UPDATE:

更新:

Modified the code based on this answerto get rid of obsolete methods.

根据此答案修改了代码以摆脱过时的方法。

You can use the Security namespace to check this:

您可以使用 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
    }

}

As far as getting those permission, you are going to have to ask the user to do that for you somehow. If you could programatically do this, then we would all be in trouble ;)

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

回答by Iain

When your code does the following:

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

  1. Checks the current user has permission to do something.
  2. Carries out the action that needs the entitlements checked in 1.
  1. 检查当前用户是否有权做某事。
  2. 执行需要在 1 中签入的权利的操作。

You run the risk that the permissions change between 1and 2because you can't predict what else will be happening on the system at runtime. Therefore, your code should handle the situation where an UnauthorisedAccessExceptionis thrown even if you have previously checked permissions.

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

Note that the SecurityManagerclass is used to check CAS permissions and doesn't actually check with the OS whether the current user has write access to the specified location (through ACLs and ACEs). As such, IsGrantedwill always return true for locally running applications.

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

Example(derived from Josh's example):

示例(源自Josh 的示例):

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

It's tricky and not recommendedto try to programatically calculate the effective permissions from the folder based on the raw ACLs (which are all that are available through the System.Security.AccessControlclasses). Other answers on Stack Overflow and the wider web recommend trying to carry out the action to know whether permission is allowed. Thispost sums up what's required to implement the permission calculation and should be enough to put you off from doing this.

尝试以编程方式根据原始 ACL(可通过System.Security.AccessControl类获得的所有 ACL)从文件夹中计算有效权限是很棘手的,不建议这样做。Stack Overflow 和更广泛的网络上的其他答案建议尝试执行操作以了解是否允许许可。这篇文章总结了实现权限计算所需的内容,应该足以让您避免这样做。

回答by RockWorld

You can try following code block to check if the directory is having Write Access.

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

It checks the FileSystemAccessRule.

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

回答by Pablonete

Sorry, but none of the previous solutions helped me. I need to check both sides: SecurityManager and SO permissions. I have learned a lot with Josh code and with iain answer, but I'm afraid I need to use Rakesh code (also thanks to him). Only one bug: I found that he only checks for Allow and not for Deny permissions. So my proposal is:

对不起,但以前的解决方案都没有帮助我。我需要检查双方: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!

回答by JGU

None of these worked for me.. they return as true, even when they aren't. The problem is, you have to test the available permission against the current process user rights, this tests for file creation rights, just change the FileSystemRights clause to 'Write' to test write access..

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

回答by MaxOvrdrv

Since this isn't closed, i would like to submit a new entry for anyone looking to have something working properly for them... using an amalgamation of what i found here, as well as using DirectoryServices to debug the code itself and find the proper code to use, here's what i found that works for me in every situation... note that my solution extends DirectoryInfo object... :

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

回答by xmen

Its a fixed version of MaxOvrdrv's Code.

它是 MaxOvrdrv代码的固定版本。

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

回答by jinzai

Wow...there is a lot of low-level security code in this thread -- most of which did not work for me, either -- although I learned a lot in the process. One thing that I learned is that most of this code is not geared to applications seeking per user access rights -- it is for Administrators wanting to alter rights programmatically, which -- as has been pointed out -- is nota good thing. As a developer, I cannot use the "easy way out" -- by running as Administrator -- which -- I am not one on the machine that runs the code, nor are my users -- so, as clever as these solutions are -- they are not for my situation, and probably not for most rank and file developers, either.

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

Like most posters of this type of question -- I initially felt it was "hackey", too -- I have since decided that it is perfectly alright to try it and let the possible exception tell you exactly what the user's rights are -- because the information I got did not tell me what the rights actually were. The code below -- did.

像大多数此类问题的海报一样——我最初也觉得它是“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

End Function

结束函数