it-swarm.com.de

C # Test, ob der Benutzer Schreibzugriff auf einen Ordner hat

Ich muss testen, ob ein Benutzer in einen Ordner schreiben kann, bevor ich es tatsächlich versuche.

Ich habe die folgende Methode (in C # 2.0) implementiert, die versucht, die Sicherheitsberechtigungen für den Ordner mit der Methode Directory.GetAccessControl () abzurufen.

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

Als ich googelte, wie man auf Schreibzugriff testet, tauchte nichts dergleichen auf und es schien sehr kompliziert zu sein, die Berechtigungen in Windows tatsächlich zu testen. Ich mache mir Sorgen, dass ich die Dinge zu stark vereinfache und dass diese Methode nicht robust ist, obwohl sie zu funktionieren scheint.

Funktioniert meine Methode zum Testen, ob der aktuelle Benutzer über Schreibzugriff verfügt, ordnungsgemäß?

173
Chris B

Dies ist eine absolut gültige Methode, um den Ordnerzugriff in C # zu überprüfen. Der einzige Ort, an dem es herunterfallen könnte, ist, wenn Sie dies in einer engen Schleife aufrufen müssen, in der der Overhead einer Ausnahme ein Problem sein kann .

Es wurden bereits andere ähnlicheFragen gestellt.

59
Ash

Ich weiß es zu schätzen, dass es für diesen Beitrag etwas spät ist, aber Sie werden diesen Code vielleicht nützlich finden.

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

Ziehen Sie das in eine Konsolen-App und prüfen Sie, ob es das tut, was Sie brauchen.

61
Duncan Howe
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;
    }
}
58
priit

Ich habe die meisten von ihnen aus dem gleichen Grund ausprobiert, aber sie führen zu Fehlalarmen. Es reicht nicht aus, das Verzeichnis auf eine verfügbare Berechtigung zu prüfen. Sie müssen überprüfen, ob der angemeldete Benutzer Mitglied einer Gruppe ist, die über diese Berechtigung verfügt Genehmigung. Dazu rufen Sie die Benutzeridentität ab und prüfen, ob sie Mitglied einer Gruppe ist, die die FileSystemAccessRule IdentityReference enthält. Ich habe das getestet, funktioniert einwandfrei ..

    /// <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;
    }
20
JGU

Zum Beispiel funktioniert diese Methode für alle Benutzer (Builtin\Users) einwandfrei - viel Spaß.

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

Meiner Meinung nach besteht die einzige 100% zuverlässige Möglichkeit, zu testen, ob Sie in ein Verzeichnis schreiben können, darin, tatsächlich in dieses Verzeichnis zu schreiben und schließlich Ausnahmen abzufangen.

11
Darin Dimitrov

Versuche dies:

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

Ihr Code erhält das DirectorySecurity für ein bestimmtes Verzeichnis und behandelt eine Ausnahme (da Sie keinen Zugriff auf die Sicherheitsinformationen haben) korrekt. In Ihrem Beispiel fragen Sie das zurückgegebene Objekt jedoch nicht ab, um festzustellen, welcher Zugriff zulässig ist - und ich denke, Sie müssen dies hinzufügen.

6
Vinay Sajip

Hier ist eine modifizierte Version von CsabaSs Antwort , die explizite Verweigerungsregeln berücksichtigt. Die Funktion durchsucht alle FileSystemAccessRules für ein Verzeichnis und prüft, ob sich der aktuelle Benutzer in einer Rolle befindet, die Zugriff auf ein Verzeichnis hat. Wenn keine solchen Rollen gefunden werden oder der Benutzer eine Rolle mit verweigertem Zugriff hat, gibt die Funktion false zurück. Übergeben Sie zum Überprüfen der Leserechte FileSystemRights.Read an die Funktion. Übergeben Sie für Schreibrechte FileSystemRights.Write. Wenn Sie die Rechte eines beliebigen Benutzers und nicht die des aktuellen Benutzers überprüfen möchten, ersetzen Sie die gewünschte WindowsIdentity durch die WindowsIdentity currentUser. Ich würde auch davon abraten, sich auf Funktionen wie diese zu verlassen, um festzustellen, ob der Benutzer das Verzeichnis sicher verwenden kann. Diese Antwort erklärt perfekt warum.

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

Ich habe die gleiche Funktion verwendet, um zu überprüfen, ob die Datei einen Schreibzugriff hat:

    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;
        }
    }
5
Bruno Bieri

Sie können versuchen, den folgenden Codeblock zu verwenden, um zu überprüfen, ob das Verzeichnis über Schreibzugriff verfügt. Es überprüft die 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 
}
3
RockWorld

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

Sehr nützliche Klasse, überprüfen Sie die verbesserte Version in den folgenden Nachrichten.

2
user187083

Die obigen Lösungen sind gut, aber für mich finde ich diesen Code einfach und praktikabel. Erstellen Sie einfach eine temporäre Datei. Wenn die Datei erstellt wird, hat der mittlere Benutzer Schreibzugriff.

        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;
        }
2
Ali Asad

Sie haben eine potenzielle Racebedingung in Ihrem Code. Was passiert, wenn der Benutzer Berechtigungen zum Schreiben in den Ordner hat, wenn Sie dies überprüfen, aber bevor der Benutzer tatsächlich in den Ordner schreibt, wird diese Berechtigung entzogen? Das Schreiben löst eine Ausnahme aus, die Sie abfangen und behandeln müssen. Die Erstprüfung ist also sinnlos. Sie können auch einfach schreiben und alle Ausnahmen behandeln. Dies ist das Standardmuster für Ihre Situation.

2
ShellShock

Der bloße Versuch, auf die betreffende Datei zuzugreifen, reicht nicht unbedingt aus. Der Test wird mit den Berechtigungen des Benutzers ausgeführt, der das Programm ausführt. Dabei handelt es sich nicht unbedingt um die Benutzerberechtigungen, mit denen Sie testen möchten.

1
Mort

Ich hatte das gleiche Problem: Wie überprüfe ich, ob ich in einem bestimmten Verzeichnis lesen/schreiben kann? Am Ende hatte ich die einfache Lösung, um ... es tatsächlich zu testen. Hier ist meine einfache, aber effektive Lösung.

 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

}

Ich hoffe es hilft !

0
l.raimondi

Ich stimme Ash zu, das sollte in Ordnung sein. Alternativ können Sie deklaratives CAS verwenden und tatsächlich verhindern, dass das Programm überhaupt ausgeführt wird, wenn sie keinen Zugriff haben.

Ich glaube, einige der CAS-Funktionen sind in C # 4.0 möglicherweise nicht vorhanden, da ich nicht sicher bin, ob dies ein Problem darstellt oder nicht.

0
Ian

Ich konnte GetAccessControl () nicht dazu bringen, unter Windows 7 eine Ausnahme auszulösen, wie in der akzeptierten Antwort empfohlen.

Am Ende habe ich eine Variation von sdds's verwendet. Antwort:

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

Hoffe das hilft.

0
Patrick