C # Test si l'Utilisateur a accès en écriture à un dossier

j'ai besoin de tester si un utilisateur peut écrire dans un dossier avant de tenter de le faire.

j'ai implémenté la méthode suivante (en C# 2.0) qui tente de récupérer les permissions de sécurité pour le dossier en utilisant le répertoire .Méthode GetAccessControl () .

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

quand je googlais comment tester pour l'accès en écriture rien de tel n'est venu et il a semblé très compliqué de tester réellement les permissions en Windows. Je m'inquiète du fait que je simplifie trop les choses et que cette méthode n'est pas robuste, bien qu'elle semble fonctionner.

est-ce que ma méthode pour tester si l'utilisateur actuel a accès en écriture fonctionne correctement?

160
demandé sur Chris B 2009-09-11 14:14:55

18 réponses

C'est une façon parfaitement valide de vérifier l'accès aux dossiers dans C#. Le seul endroit où il pourrait tomber est si vous avez besoin d'appeler cela dans une boucle serrée où les frais généraux d'une exception peut être un problème.

Il y a eu d'autres similaires questions posées auparavant.

56
répondu Ash 2017-05-23 12:34:33

j'ai conscience qu'il est un peu tard dans la journée pour ce post, mais vous pourriez trouver ce morceau de code utile.

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

déposez ça dans une application de Console et voyez si elle fait ce dont vous avez besoin.

58
répondu Duncan Howe 2018-01-02 12:12:55
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;
    }
}
49
répondu priit 2014-10-17 18:27:01

j'ai essayé la plupart de ceux-ci, mais ils donnent des faux positifs, Tous pour la même raison.. Il n'est pas suffisant pour tester le répertoire d'une autorisation, vous devez vérifier que l'utilisateur connecté est un membre d'un groupe qui dispose que l'autorisation. Pour ce faire, vous obtenez l'identité de l'utilisateur, et vérifier si elle est membre d'un groupe qui contient le FileSystemAccessRule IdentityReference. J'ai testé, fonctionne parfaitement..

    /// <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;
    }
17
répondu JGU 2014-02-24 19:00:15

par exemple pour tous les utilisateurs (Builtin\Users), cette méthode fonctionne fine - enjoy.

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
répondu UGEEN 2012-06-22 13:50:33

IMHO le seul moyen fiable à 100% de tester si vous pouvez écrire dans un répertoire est d'y écrire et éventuellement de saisir des exceptions.

8
répondu Darin Dimitrov 2009-09-11 10:16:48

essayez ceci:

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");
}
7
répondu CsabaS 2012-10-19 13:04:58

votre code reçoit le DirectorySecurity pour un répertoire donné, et gère une exception (en raison de votre manque d'accès aux informations de sécurité) correctement. Cependant, dans votre exemple, il n'est pas d'interroger l'objet retourné pour voir ce que l'accès est autorisé - et je pense que vous devez l'ajouter.

6
répondu Vinay Sajip 2009-09-11 10:23:27

j'ai utilisé la même fonction pour vérifier si le fichier hasWriteAccess:

    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
répondu Bruno Bieri 2012-07-10 05:18:40

Voici une version modifiée de réponse de CsabaS , qui tient compte des règles explicites de refus d'accès. La fonction passe en revue toutes les règles FileSystemAccessRules pour un répertoire, et vérifie si l'utilisateur courant est dans un rôle qui a accès à un répertoire. Si aucun rôle de ce type n'est trouvé ou si l'utilisateur se trouve dans un rôle dont l'accès est refusé, la fonction retourne false. Pour vérifier les droits de lecture, passer FileSystemRights.Lire à la fonction; pour les droits d'écriture, passer FileSystemRights.Écrire. Si vous voulez vérifier les droits d'un utilisateur arbitraire et non ceux de l'utilisateur actuel, remplacez la WindowsIdentity de l'utilisateur actuel par la WindowsIdentity désirée. Je conseillerais également de ne pas se fier à des fonctions comme celle-ci pour déterminer si l'utilisateur peut utiliser le répertoire en toute sécurité. Ce réponse explique parfaitement pourquoi.

    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;
    }
5
répondu sdds 2017-05-23 12:17:58

vous pouvez essayer de suivre le bloc de code pour vérifier si le répertoire a accès en écriture. Il vérifie la règle D'accès au système de fichiers.

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
répondu RockWorld 2014-02-25 16:06:39

vous avez une condition de course potentielle dans votre code--que se passe-t-il si l'Utilisateur a les permissions d'écrire dans le dossier quand vous vérifiez, mais avant que l'utilisateur écrit réellement dans le dossier Cette permission est retirée? L'écriture lancera une exception que vous aurez besoin d'attraper et de gérer. Si la vérification initiale est inutile. Autant écrire et gérer les exceptions. C'est le modèle standard pour votre situation.

2
répondu 2009-09-11 11:08:05

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

classe très utile, vérifier la version améliorée dans les messages ci-dessous.

2
répondu 2009-10-09 10:10:03

simplement essayer d'accéder au fichier en question n'est pas nécessairement suffisant. Le test sera exécuté avec les privilèges de l'utilisateur exécutant le programme - Qui n'est pas nécessairement l'utilisateur les autorisations que vous souhaitez tester.

1
répondu Mort 2011-06-17 10:12:29

ci-dessus les solutions sont bonnes mais pour moi, je trouve ce code simple et pratique. Il suffit de créer un fichier temporaire. Si le fichier est créé, son utilisateur moyen a l'accès en écriture.

        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;
        }
1
répondu Ali Asad 2018-01-25 08:00:29

je suis d'accord avec Ash, ça devrait aller. Vous pouvez également utiliser le cas déclaratif et empêcher réellement le programme de fonctionner en premier lieu s'ils n'ont pas accès.

je crois que certaines des caractéristiques des SAE peuvent ne pas être présentes dans C# 4.0 d'après ce que j'ai entendu, je ne suis pas sûr que ce soit un problème ou non.

0
répondu Ian 2009-09-11 10:21:55

Je n'ai pas pu obtenir de GetAccessControl() de lancer une exception sur Windows 7 comme recommandé dans la réponse acceptée.

j'ai fini par utiliser une variation de sdds réponse:

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

Espérons que cette aide.

0
répondu Patrick 2017-05-23 12:10:36

j'ai fait face au même problème: comment vérifier si je peux lire/écrire dans un répertoire particulier. J'ai fini avec la solution de facilité...en fait l'essai. Voici ma solution simple mais efficace.

 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

}

Espère que cela aide !

0
répondu l.raimondi 2016-01-08 14:39:25