在。net中检查目录和文件写入权限

时间:2022-07-02 16:48:54

In my .NET 2.0 application, I need to check if sufficient permissions exist to create and write to files to a directory. To this end, I have the following function that attempts to create a file and write a single byte to it, deleting itself afterwards to test that permissions do exist.

在我的。net 2.0应用程序中,我需要检查是否存在足够的权限来创建和写入到目录的文件。为此,我有以下函数,它尝试创建一个文件并向其写入一个字节,然后删除自己以测试是否存在权限。

I figured the best way to check was to actually try and do it, catching any exceptions that occur. I'm not particularly happy about the general Exception catch though, so is there a better or perhaps a more accepted way of doing this?

我认为最好的检查方法是试着去做,找出任何可能发生的异常。我不太喜欢一般的例外情况,那么有没有更好的或者更容易被接受的方法呢?

private const string TEMP_FILE = "\\tempFile.tmp";

/// <summary>
/// Checks the ability to create and write to a file in the supplied directory.
/// </summary>
/// <param name="directory">String representing the directory path to check.</param>
/// <returns>True if successful; otherwise false.</returns>
private static bool CheckDirectoryAccess(string directory)
{
    bool success = false;
    string fullPath = directory + TEMP_FILE;

    if (Directory.Exists(directory))
    {
        try
        {
            using (FileStream fs = new FileStream(fullPath, FileMode.CreateNew, 
                                                            FileAccess.Write))
            {
                fs.WriteByte(0xff);
            }

            if (File.Exists(fullPath))
            {
                File.Delete(fullPath);
                success = true;
            }
        }
        catch (Exception)
        {
            success = false;
        }
    }

9 个解决方案

#1


21  

The answers by Richard and Jason are sort of in the right direction. However what you should be doing is computing the effective permissions for the user identity running your code. None of the examples above correctly account for group membership for example.

理查德和杰森的回答是正确的。但是,您应该做的是计算运行代码的用户标识的有效权限。上面的示例中没有一个正确地解释了组成员关系。

I'm pretty sure Keith Brown had some code to do this in his wiki version (offline at this time) of The .NET Developers Guide to Windows Security. This is also discussed in reasonable detail in his Programming Windows Security book.

我很确定Keith Brown在他的。net开发人员指南Windows安全的wiki版本(当时离线)中有一些代码。在他的编程Windows安全手册中也讨论了这个问题。

Computing effective permissions is not for the faint hearted and your code to attempt creating a file and catching the security exception thrown is probably the path of least resistance.

计算有效的权限不适合胆小的人,而您的代码试图创建一个文件并捕获抛出的安全异常可能是最小阻力的路径。

#2


44  

Directory.GetAcessControl(path) does what you are asking for.

getacesscontrol (path)执行您所要求的操作。

public static bool HasWritePermissionOnDir(string path)
{
    var writeAllow = false;
    var writeDeny = false;
    var accessControlList = Directory.GetAccessControl(path);
    if (accessControlList == null)
        return false;
    var accessRules = accessControlList.GetAccessRules(true, true, 
                                typeof(System.Security.Principal.SecurityIdentifier));
    if (accessRules ==null)
        return false;

    foreach (FileSystemAccessRule rule in accessRules)
    {
        if ((FileSystemRights.Write & rule.FileSystemRights) != FileSystemRights.Write) 
            continue;

        if (rule.AccessControlType == AccessControlType.Allow)
            writeAllow = true;
        else if (rule.AccessControlType == AccessControlType.Deny)
            writeDeny = true;
    }

    return writeAllow && !writeDeny;
}

(FileSystemRights.Write & rights) == FileSystemRights.Write is using something called "Flags" btw which if you don't know what it is you should really read up on :)

(FileSystemRights。写入&权限)=文件系统权限。Write使用的是一种叫做“Flags”的东西,顺便说一句,如果你不知道它是什么,你应该仔细阅读:

#3


29  

Deny takes precedence over Allow. Local rules take precedence over inherited rules. I have seen many solutions (including some answers shown here), but none of them takes into account whether rules are inherited or not. Therefore I suggest the following approach that considers rule inheritance (neatly wrapped into a class):

拒绝优先于允许。本地规则优先于继承的规则。我已经看到了许多解决方案(包括这里显示的一些答案),但是没有一个解决方案考虑到规则是否继承。因此,我建议采用以下方法考虑规则继承(整齐地封装到类中):

public class CurrentUserSecurity
{
    WindowsIdentity _currentUser;
    WindowsPrincipal _currentPrincipal;

    public CurrentUserSecurity()
    {
        _currentUser = WindowsIdentity.GetCurrent();
        _currentPrincipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
    }

    public bool HasAccess(DirectoryInfo directory, FileSystemRights right)
    {
        // Get the collection of authorization rules that apply to the directory.
        AuthorizationRuleCollection acl = directory.GetAccessControl()
            .GetAccessRules(true, true, typeof(SecurityIdentifier));
        return HasFileOrDirectoryAccess(right, acl);
    }

    public bool HasAccess(FileInfo file, FileSystemRights right)
    {
        // Get the collection of authorization rules that apply to the file.
        AuthorizationRuleCollection acl = file.GetAccessControl()
            .GetAccessRules(true, true, typeof(SecurityIdentifier));
        return HasFileOrDirectoryAccess(right, acl);
    }

    private bool HasFileOrDirectoryAccess(FileSystemRights right,
                                          AuthorizationRuleCollection acl)
    {
        bool allow = false;
        bool inheritedAllow = false;
        bool inheritedDeny = false;

        for (int i = 0; i < acl.Count; i++) {
            var currentRule = (FileSystemAccessRule)acl[i];
            // If the current rule applies to the current user.
            if (_currentUser.User.Equals(currentRule.IdentityReference) ||
                _currentPrincipal.IsInRole(
                                (SecurityIdentifier)currentRule.IdentityReference)) {

                if (currentRule.AccessControlType.Equals(AccessControlType.Deny)) {
                    if ((currentRule.FileSystemRights & right) == right) {
                        if (currentRule.IsInherited) {
                            inheritedDeny = true;
                        } else { // Non inherited "deny" takes overall precedence.
                            return false;
                        }
                    }
                } else if (currentRule.AccessControlType
                                                  .Equals(AccessControlType.Allow)) {
                    if ((currentRule.FileSystemRights & right) == right) {
                        if (currentRule.IsInherited) {
                            inheritedAllow = true;
                        } else {
                            allow = true;
                        }
                    }
                }
            }
        }

        if (allow) { // Non inherited "allow" takes precedence over inherited rules.
            return true;
        }
        return inheritedAllow && !inheritedDeny;
    }
}

However, I made the experience that this does not always work on remote computers as you will not always have the right to query the file access rights there. The solution in that case is to try; possibly even by just trying to create a temporary file, if you need to know the access right before working with the "real" files.

然而,我的经验是,这并不总是适用于远程计算机,因为您并不总是有权查询那里的文件访问权限。在这种情况下,解决办法是尝试;如果您需要在处理“真实”文件之前了解访问权限,甚至可以尝试创建一个临时文件。

#4


18  

The accepted answer by Kev to this question doesn't actually give any code, it just points to other resources that I don't have access to. So here's my best attempt at the function. It actually checks that the permission it's looking at is a "Write" permission and that the current user belongs to the appropriate group.

Kev对这个问题的公认答案实际上并没有给出任何代码,它只是指向我无法访问的其他资源。这是我对这个函数的最好尝试。它实际上检查它正在查看的权限是“写”权限,并且当前用户属于适当的组。

It might not be complete with regard to network paths or whatever, but it's good enough for my purpose, checking local configuration files under "Program Files" for writability:

它可能在网络路径或其他方面不完整,但对于我的目的来说已经足够了,在“程序文件”下检查本地配置文件以获得可写性:

using System.Security.Principal;
using System.Security.AccessControl;

private static bool HasWritePermission(string FilePath)
{
    try
    {
        FileSystemSecurity security;
        if (File.Exists(FilePath))
        {
            security = File.GetAccessControl(FilePath);
        }
        else
        {
            security = Directory.GetAccessControl(Path.GetDirectoryName(FilePath));
        }
        var rules = security.GetAccessRules(true, true, typeof(NTAccount));

        var currentuser = new WindowsPrincipal(WindowsIdentity.GetCurrent());
        bool result = false;
        foreach (FileSystemAccessRule rule in rules)
        {
            if (0 == (rule.FileSystemRights &
                (FileSystemRights.WriteData | FileSystemRights.Write)))
            {
                continue;
            }

            if (rule.IdentityReference.Value.StartsWith("S-1-"))
            {
                var sid = new SecurityIdentifier(rule.IdentityReference.Value);
                if (!currentuser.IsInRole(sid))
                {
                    continue;
                }
            }
            else
            {
                if (!currentuser.IsInRole(rule.IdentityReference.Value))
                {
                    continue;
                }
            }

            if (rule.AccessControlType == AccessControlType.Deny)
                return false;
            if (rule.AccessControlType == AccessControlType.Allow)
                result = true;
        }
        return result;
    }
    catch
    {
        return false;
    }
}

#5


5  

IMO, you need to work with such directories as usual, but instead of checking permissions before use, provide the correct way to handle UnauthorizedAccessException and react accordingly. This method is easier and much less error prone.

在我看来,您需要像往常一样使用这些目录,但是在使用之前不要检查权限,而是提供正确的方式来处理未经授权的accessexception并作出相应的反应。这种方法更简单,更不容易出错。

#6


2  

Try working with this C# snippet I just crafted:

请尝试使用我刚刚编写的c#代码片段:

using System;
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string directory = @"C:\downloads";

            DirectoryInfo di = new DirectoryInfo(directory);

            DirectorySecurity ds = di.GetAccessControl();

            foreach (AccessRule rule in ds.GetAccessRules(true, true, typeof(NTAccount)))
            {
                Console.WriteLine("Identity = {0}; Access = {1}", 
                              rule.IdentityReference.Value, rule.AccessControlType);
            }
        }
    }
}

And here's a reference you could also look at. My code might give you an idea as to how you could check for permissions before attempting to write to a directory.

这里还有一个参考资料。我的代码可能会告诉您如何在尝试写入目录之前检查权限。

#7


0  

In my case ( check the readonly for shared network folders) working only http://www.codeproject.com/Articles/14402/Testing-File-Access-Rights-in-NET

在我的例子中(检查共享网络文件夹的readonly)只工作http://www.codeproject.com/articles/14402/testing-file - access - right - In - net

#8


0  

according to this link: http://www.authorcode.com/how-to-check-file-permission-to-write-in-c/

根据这个链接:http://www.authorcode.com/howto -check-file- permissitowritein -c/

it's easier to use existing class SecurityManager

使用现有的类SecurityManager更容易

string FileLocation = @"C:\test.txt";
FileIOPermission writePermission = new FileIOPermission(FileIOPermissionAccess.Write, FileLocation);
if (SecurityManager.IsGranted(writePermission))
{
  // you have permission
}
else
{
 // permission is required!
}

but it seems it's been obsoleted, it is suggested to use PermissionSet instead.

但似乎已经被淘汰了,建议改用PermissionSet。

[Obsolete("IsGranted is obsolete and will be removed in a future release of the .NET Framework.  Please use the PermissionSet property of either AppDomain or Assembly instead.")]

#9


-1  

private static void GrantAccess(string file)
        {
            bool exists = System.IO.Directory.Exists(file);
            if (!exists)
            {
                DirectoryInfo di = System.IO.Directory.CreateDirectory(file);
                Console.WriteLine("The Folder is created Sucessfully");
            }
            else
            {
                Console.WriteLine("The Folder already exists");
            }
            DirectoryInfo dInfo = new DirectoryInfo(file);
            DirectorySecurity dSecurity = dInfo.GetAccessControl();
            dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
            dInfo.SetAccessControl(dSecurity);

        }

#1


21  

The answers by Richard and Jason are sort of in the right direction. However what you should be doing is computing the effective permissions for the user identity running your code. None of the examples above correctly account for group membership for example.

理查德和杰森的回答是正确的。但是,您应该做的是计算运行代码的用户标识的有效权限。上面的示例中没有一个正确地解释了组成员关系。

I'm pretty sure Keith Brown had some code to do this in his wiki version (offline at this time) of The .NET Developers Guide to Windows Security. This is also discussed in reasonable detail in his Programming Windows Security book.

我很确定Keith Brown在他的。net开发人员指南Windows安全的wiki版本(当时离线)中有一些代码。在他的编程Windows安全手册中也讨论了这个问题。

Computing effective permissions is not for the faint hearted and your code to attempt creating a file and catching the security exception thrown is probably the path of least resistance.

计算有效的权限不适合胆小的人,而您的代码试图创建一个文件并捕获抛出的安全异常可能是最小阻力的路径。

#2


44  

Directory.GetAcessControl(path) does what you are asking for.

getacesscontrol (path)执行您所要求的操作。

public static bool HasWritePermissionOnDir(string path)
{
    var writeAllow = false;
    var writeDeny = false;
    var accessControlList = Directory.GetAccessControl(path);
    if (accessControlList == null)
        return false;
    var accessRules = accessControlList.GetAccessRules(true, true, 
                                typeof(System.Security.Principal.SecurityIdentifier));
    if (accessRules ==null)
        return false;

    foreach (FileSystemAccessRule rule in accessRules)
    {
        if ((FileSystemRights.Write & rule.FileSystemRights) != FileSystemRights.Write) 
            continue;

        if (rule.AccessControlType == AccessControlType.Allow)
            writeAllow = true;
        else if (rule.AccessControlType == AccessControlType.Deny)
            writeDeny = true;
    }

    return writeAllow && !writeDeny;
}

(FileSystemRights.Write & rights) == FileSystemRights.Write is using something called "Flags" btw which if you don't know what it is you should really read up on :)

(FileSystemRights。写入&权限)=文件系统权限。Write使用的是一种叫做“Flags”的东西,顺便说一句,如果你不知道它是什么,你应该仔细阅读:

#3


29  

Deny takes precedence over Allow. Local rules take precedence over inherited rules. I have seen many solutions (including some answers shown here), but none of them takes into account whether rules are inherited or not. Therefore I suggest the following approach that considers rule inheritance (neatly wrapped into a class):

拒绝优先于允许。本地规则优先于继承的规则。我已经看到了许多解决方案(包括这里显示的一些答案),但是没有一个解决方案考虑到规则是否继承。因此,我建议采用以下方法考虑规则继承(整齐地封装到类中):

public class CurrentUserSecurity
{
    WindowsIdentity _currentUser;
    WindowsPrincipal _currentPrincipal;

    public CurrentUserSecurity()
    {
        _currentUser = WindowsIdentity.GetCurrent();
        _currentPrincipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
    }

    public bool HasAccess(DirectoryInfo directory, FileSystemRights right)
    {
        // Get the collection of authorization rules that apply to the directory.
        AuthorizationRuleCollection acl = directory.GetAccessControl()
            .GetAccessRules(true, true, typeof(SecurityIdentifier));
        return HasFileOrDirectoryAccess(right, acl);
    }

    public bool HasAccess(FileInfo file, FileSystemRights right)
    {
        // Get the collection of authorization rules that apply to the file.
        AuthorizationRuleCollection acl = file.GetAccessControl()
            .GetAccessRules(true, true, typeof(SecurityIdentifier));
        return HasFileOrDirectoryAccess(right, acl);
    }

    private bool HasFileOrDirectoryAccess(FileSystemRights right,
                                          AuthorizationRuleCollection acl)
    {
        bool allow = false;
        bool inheritedAllow = false;
        bool inheritedDeny = false;

        for (int i = 0; i < acl.Count; i++) {
            var currentRule = (FileSystemAccessRule)acl[i];
            // If the current rule applies to the current user.
            if (_currentUser.User.Equals(currentRule.IdentityReference) ||
                _currentPrincipal.IsInRole(
                                (SecurityIdentifier)currentRule.IdentityReference)) {

                if (currentRule.AccessControlType.Equals(AccessControlType.Deny)) {
                    if ((currentRule.FileSystemRights & right) == right) {
                        if (currentRule.IsInherited) {
                            inheritedDeny = true;
                        } else { // Non inherited "deny" takes overall precedence.
                            return false;
                        }
                    }
                } else if (currentRule.AccessControlType
                                                  .Equals(AccessControlType.Allow)) {
                    if ((currentRule.FileSystemRights & right) == right) {
                        if (currentRule.IsInherited) {
                            inheritedAllow = true;
                        } else {
                            allow = true;
                        }
                    }
                }
            }
        }

        if (allow) { // Non inherited "allow" takes precedence over inherited rules.
            return true;
        }
        return inheritedAllow && !inheritedDeny;
    }
}

However, I made the experience that this does not always work on remote computers as you will not always have the right to query the file access rights there. The solution in that case is to try; possibly even by just trying to create a temporary file, if you need to know the access right before working with the "real" files.

然而,我的经验是,这并不总是适用于远程计算机,因为您并不总是有权查询那里的文件访问权限。在这种情况下,解决办法是尝试;如果您需要在处理“真实”文件之前了解访问权限,甚至可以尝试创建一个临时文件。

#4


18  

The accepted answer by Kev to this question doesn't actually give any code, it just points to other resources that I don't have access to. So here's my best attempt at the function. It actually checks that the permission it's looking at is a "Write" permission and that the current user belongs to the appropriate group.

Kev对这个问题的公认答案实际上并没有给出任何代码,它只是指向我无法访问的其他资源。这是我对这个函数的最好尝试。它实际上检查它正在查看的权限是“写”权限,并且当前用户属于适当的组。

It might not be complete with regard to network paths or whatever, but it's good enough for my purpose, checking local configuration files under "Program Files" for writability:

它可能在网络路径或其他方面不完整,但对于我的目的来说已经足够了,在“程序文件”下检查本地配置文件以获得可写性:

using System.Security.Principal;
using System.Security.AccessControl;

private static bool HasWritePermission(string FilePath)
{
    try
    {
        FileSystemSecurity security;
        if (File.Exists(FilePath))
        {
            security = File.GetAccessControl(FilePath);
        }
        else
        {
            security = Directory.GetAccessControl(Path.GetDirectoryName(FilePath));
        }
        var rules = security.GetAccessRules(true, true, typeof(NTAccount));

        var currentuser = new WindowsPrincipal(WindowsIdentity.GetCurrent());
        bool result = false;
        foreach (FileSystemAccessRule rule in rules)
        {
            if (0 == (rule.FileSystemRights &
                (FileSystemRights.WriteData | FileSystemRights.Write)))
            {
                continue;
            }

            if (rule.IdentityReference.Value.StartsWith("S-1-"))
            {
                var sid = new SecurityIdentifier(rule.IdentityReference.Value);
                if (!currentuser.IsInRole(sid))
                {
                    continue;
                }
            }
            else
            {
                if (!currentuser.IsInRole(rule.IdentityReference.Value))
                {
                    continue;
                }
            }

            if (rule.AccessControlType == AccessControlType.Deny)
                return false;
            if (rule.AccessControlType == AccessControlType.Allow)
                result = true;
        }
        return result;
    }
    catch
    {
        return false;
    }
}

#5


5  

IMO, you need to work with such directories as usual, but instead of checking permissions before use, provide the correct way to handle UnauthorizedAccessException and react accordingly. This method is easier and much less error prone.

在我看来,您需要像往常一样使用这些目录,但是在使用之前不要检查权限,而是提供正确的方式来处理未经授权的accessexception并作出相应的反应。这种方法更简单,更不容易出错。

#6


2  

Try working with this C# snippet I just crafted:

请尝试使用我刚刚编写的c#代码片段:

using System;
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string directory = @"C:\downloads";

            DirectoryInfo di = new DirectoryInfo(directory);

            DirectorySecurity ds = di.GetAccessControl();

            foreach (AccessRule rule in ds.GetAccessRules(true, true, typeof(NTAccount)))
            {
                Console.WriteLine("Identity = {0}; Access = {1}", 
                              rule.IdentityReference.Value, rule.AccessControlType);
            }
        }
    }
}

And here's a reference you could also look at. My code might give you an idea as to how you could check for permissions before attempting to write to a directory.

这里还有一个参考资料。我的代码可能会告诉您如何在尝试写入目录之前检查权限。

#7


0  

In my case ( check the readonly for shared network folders) working only http://www.codeproject.com/Articles/14402/Testing-File-Access-Rights-in-NET

在我的例子中(检查共享网络文件夹的readonly)只工作http://www.codeproject.com/articles/14402/testing-file - access - right - In - net

#8


0  

according to this link: http://www.authorcode.com/how-to-check-file-permission-to-write-in-c/

根据这个链接:http://www.authorcode.com/howto -check-file- permissitowritein -c/

it's easier to use existing class SecurityManager

使用现有的类SecurityManager更容易

string FileLocation = @"C:\test.txt";
FileIOPermission writePermission = new FileIOPermission(FileIOPermissionAccess.Write, FileLocation);
if (SecurityManager.IsGranted(writePermission))
{
  // you have permission
}
else
{
 // permission is required!
}

but it seems it's been obsoleted, it is suggested to use PermissionSet instead.

但似乎已经被淘汰了,建议改用PermissionSet。

[Obsolete("IsGranted is obsolete and will be removed in a future release of the .NET Framework.  Please use the PermissionSet property of either AppDomain or Assembly instead.")]

#9


-1  

private static void GrantAccess(string file)
        {
            bool exists = System.IO.Directory.Exists(file);
            if (!exists)
            {
                DirectoryInfo di = System.IO.Directory.CreateDirectory(file);
                Console.WriteLine("The Folder is created Sucessfully");
            }
            else
            {
                Console.WriteLine("The Folder already exists");
            }
            DirectoryInfo dInfo = new DirectoryInfo(file);
            DirectorySecurity dSecurity = dInfo.GetAccessControl();
            dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
            dInfo.SetAccessControl(dSecurity);

        }