C # Teste si l’utilisateur a un access en écriture à un dossier

Je dois 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 la méthode Directory.GetAccessControl () .

private bool hasWriteAccessToFolder(ssortingng 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; } } 

Lorsque je cherchais à tester l’access à l’écriture, rien de tel n’était apparu et il semblait très compliqué de tester les permissions dans Windows. Je crains que je simplifie trop les choses et que cette méthode ne soit pas robuste, même si cela semble fonctionner.

Est-ce que ma méthode pour tester si l’utilisateur actuel a un access en écriture fonctionne correctement?

C’est un moyen parfaitement valide pour vérifier l’access aux dossiers en C #. Le seul endroit où il pourrait tomber est si vous devez appeler cela dans une boucle serrée où la surcharge d’une exception peut être un problème.

Il y a eu d’autres questions similaires posées précédemment.

J’apprécie que ce soit un peu tard dans la journée pour cet article, mais vous pourriez trouver ce code utile.

 ssortingng path = @"c:\temp"; ssortingng 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,SsortingngComparison.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(ssortingng.Format("{0} has write access to {1}", NtAccountName, path)); } else { Console.WriteLine(ssortingng.Format("{0} does not have write access to {1}", NtAccountName, path)); } } } Console.ReadLine(); 

Déposez cela dans une application de console et voyez si elle fait ce dont vous avez besoin.

 public bool IsDirectoryWritable(ssortingng 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; } } 

J’ai essayé la plupart d’entre eux, mais ils donnent des faux positifs, tous pour la même raison. Il ne suffit pas de tester le répertoire pour obtenir une autorisation disponible, vous devez vérifier que l’utilisateur connecté est membre d’un groupe qui a cette autorisation. autorisation. Pour ce faire, vous obtenez l’identité des utilisateurs et vérifiez s’il s’agit d’un membre d’un groupe contenant l’identité FileSystemAccessRule IdentityReference. J’ai testé cela, fonctionne parfaitement

  ///  /// Test a directory for create file access permissions ///  /// Full path to directory  /// File System right tested /// State [bool] public static bool DirectoryHasPermission(ssortingng DirectoryPath, FileSystemRights AccessRight) { if (ssortingng.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; } 

Par exemple pour tous les utilisateurs (Builtin \ Users), cette méthode fonctionne bien – profitez-en.

 public static bool HasFolderWritePermission(ssortingng destDir) { if(ssortingng.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; } } 

À mon humble avis, le seul moyen fiable de tester si vous pouvez écrire dans un répertoire est de lui écrire et d’y attraper des exceptions.

Essaye ça:

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

Votre code obtient DirectorySecurity pour un répertoire donné et gère une exception (car vous n’avez pas access aux informations de sécurité). Cependant, dans votre exemple, vous n’interrogez pas réellement l’object renvoyé pour voir quel access est autorisé – et je pense que vous devez append ceci.

J’ai utilisé la même fonction pour vérifier si le fichier aWriteAccess:

  private static bool HasWriteAccessToFile(ssortingng 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; } } 

Voici une version modifiée de la réponse de CsabaS , qui tient compte des règles d’access explicites au refus. La fonction passe en revue tous les FileSystemAccessRules pour un répertoire et vérifie si l’utilisateur actuel est dans un rôle qui a access à un répertoire. Si aucun de ces rôles n’est trouvé ou que l’utilisateur est dans un rôle avec un access refusé, la fonction renvoie false. Pour vérifier les droits de lecture, transmettez FileSystemRights.Read à la fonction; pour les droits d’écriture, transmettez FileSystemRights.Write. Si vous souhaitez vérifier les droits d’un utilisateur arbitraire et non les droits actuels, remplacez WindowsIdentity par l’utilisateur actuel pour WindowsIdentity souhaité. Je déconseille également d’utiliser des fonctions comme celle-ci pour déterminer si l’utilisateur peut utiliser le répertoire en toute sécurité. Cette réponse explique parfaitement pourquoi.

  public static bool UserHasDirectoryAccessRights(ssortingng 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; } 

Vous pouvez essayer de suivre le bloc de code pour vérifier si le répertoire a un access en écriture. Il vérifie la FileSystemAccessRule.

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

Vous avez une condition de concurrence potentielle dans votre code – que se passe-t-il si l’utilisateur est autorisé à écrire dans le dossier lorsque vous vérifiez, mais avant que l’utilisateur n’écrive réellement dans le dossier, cette autorisation est retirée? L’écriture lancera une exception que vous devrez attraper et gérer. La vérification initiale est donc inutile. Vous pourriez aussi bien écrire et gérer les exceptions. C’est le modèle standard pour votre situation.

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

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

Simplement essayer d’accéder au fichier en question n’est pas forcément suffisant. Le test s’exécutera avec les permissions de l’utilisateur exécutant le programme. Ce ne sont pas nécessairement les permissions utilisateur que vous souhaitez tester.

Les solutions ci-dessus sont bonnes mais pour moi, je trouve ce code simple et pratique. Créez simplement un fichier temporaire. Si le fichier est créé, son utilisateur moyen dispose d’un access en écriture.

  public static bool HasWritePermission(ssortingng 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; } 

Je suis d’accord avec Ash, ça devrait aller. Vous pouvez également utiliser le CAS déclaratif et empêcher le programme de s’exécuter s’il n’y a pas access.

Je crois que certaines des fonctionnalités CAS ne sont peut-être pas présentes dans C # 4.0 par rapport à ce que j’ai entendu, mais je ne suis pas sûr que cela puisse être un problème ou non.

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

J’ai fini par utiliser une variante de la réponse de sdds :

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

J’espère que cela t’aides.

J’ai rencontré le même problème: comment vérifier si je peux lire / écrire dans un répertoire particulier. Je me suis retrouvé avec la solution facile pour … réellement le tester. Voici ma solution simple mais efficace.

  class Program { ///  /// Tests if can read files and if any are present ///  ///  ///  private genericResponse check_canRead(ssortingng dirPath) { try { IEnumerable 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 }; } } ///  /// Tests if can wirte both files or Directory ///  ///  ///  private genericResponse check_canWrite(ssortingng dirPath) { try { ssortingng testDir = "__TESTDIR__"; Directory.CreateDirectory(ssortingng.Join("/", dirPath, testDir)); Directory.Delete(ssortingng.Join("/", dirPath, testDir)); ssortingng testFile = "__TESTFILE__.txt"; try { TextWriter tw = new StreamWriter(ssortingng.Join("/", dirPath, testFile), false); tw.WriteLine(testFile); tw.Close(); File.Delete(ssortingng.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 ssortingng msg { get; set; } } public enum genericResponseType { NothingToRead = 1, OK = 0, CannotRead = -1, CannotWriteDir = -2, CannotWriteFile = -3, ItemNotFound = -4 } 

J’espère que cela aide !