C # Verifica se l’utente ha accesso in scrittura a una cartella

Ho bisogno di verificare se un utente può scrivere su una cartella prima di tentare effettivamente di farlo.

Ho implementato il seguente metodo (in C # 2.0) che tenta di recuperare le autorizzazioni di sicurezza per la cartella utilizzando il metodo Directory.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; } } 

Quando stavo cercando su google come testare l’accesso in scrittura, non è emerso nulla del genere e sembrava davvero complicato testare le autorizzazioni in Windows. Sono preoccupato di semplificare troppo le cose e questo metodo non è robusto, anche se sembra funzionare.

Il mio metodo per verificare se l’utente corrente ha accesso in scrittura funziona correttamente?

Questo è un modo perfettamente valido per verificare l’accesso alla cartella in C #. L’unico posto in cui potrebbe cadere è se è necessario chiamare questo in un ciclo stretto in cui il sovraccarico di un’eccezione potrebbe essere un problema.

Ci sono state altre domande simili fatte in precedenza.

Apprezzo che questo post sia un po ‘tardo, ma potresti trovare utile questo bit di codice.

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

Rilasciarlo in un’app Console e vedere se fa ciò di cui hai bisogno.

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

Ho provato la maggior parte di questi, ma danno falsi positivi, tutti per lo stesso motivo. Non è sufficiente testare la directory per un permesso disponibile, devi controllare che l’utente che ha effettuato l’accesso sia membro di un gruppo che ha authorization. Per fare ciò si ottiene l’identity framework dell’utente e si controlla se si tratta di un membro di un gruppo che contiene FileSystemAccessRule IdentityReference. Ho provato questo, funziona perfettamente ..

  ///  /// Test a directory for create file access permissions ///  /// Full path to directory  /// File System right tested /// State [bool] 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; } 

Ad esempio per tutti gli utenti (Builtin \ Users), questo metodo funziona bene: divertiti.

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

IMHO l’unico modo affidabile al 100% per testare se è ansible scrivere in una directory è in realtà scrivere su di esso e alla fine rilevare le eccezioni.

Prova questo:

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

Il tuo codice ottiene la DirectorySecurity per una determinata directory e gestisce un’eccezione (a causa del fatto che non hai accesso alle informazioni sulla sicurezza) correttamente. Tuttavia, nel tuo esempio non stai effettivamente interrogando l’object restituito per vedere quale accesso è consentito – e penso che sia necessario aggiungerlo.

Ho usato la stessa funzione per verificare se il file 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; } } 

Ecco una versione modificata della risposta di CsabaS , che spiega le regole esplicite di accesso negato. La funzione passa attraverso tutte le FileSystemAccessRules per una directory e controlla se l’utente corrente ha un ruolo che ha accesso a una directory. Se non vengono trovati tali ruoli o l’utente ha un ruolo con accesso negato, la funzione restituisce false. Per controllare i diritti di lettura, passare FileSystemRights.Read alla funzione; per i diritti di scrittura, passare FileSystemRights.Write. Se si desidera verificare i diritti di un utente arbitrario e non quelli attuali, sostituire l’ID utente corrente di WindowsIdentity per WindowsIdentity desiderato. Vorrei anche sconsigliare di fare affidamento su funzioni come questa per determinare se l’utente può tranquillamente utilizzare la directory. Questa risposta spiega perfettamente il perché.

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

Puoi provare il seguente blocco di codice per verificare se la directory sta avendo accesso in scrittura. Controlla il 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 } 

Hai una potenziale condizione di competizione nel tuo codice – cosa succede se l’utente ha le autorizzazioni per scrivere nella cartella quando controlli, ma prima che l’utente scriva effettivamente nella cartella questa authorization viene ritirata? La scrittura genererà un’eccezione che dovrai catturare e gestire. Quindi il controllo iniziale è inutile. Potresti anche solo scrivere e gestire eventuali eccezioni. Questo è lo schema standard per la tua situazione.

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

Classe molto utile, controlla la versione migliorata nei messaggi qui sotto.

Cercare semplicemente di accedere al file in questione non è necessariamente sufficiente. Il test verrà eseguito con le autorizzazioni dell’utente che esegue il programma. Non sono necessariamente le autorizzazioni utente a cui si desidera eseguire il test.

Le soluzioni di cui sopra sono buone, ma per me, trovo questo codice semplice e funzionale. Basta creare un file temporaneo. Se il file è stato creato, il suo utente medio ha l’accesso in scrittura.

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

Sono d’accordo con Ash, dovrebbe andare bene. In alternativa è ansible utilizzare CAS dichiarativo e impedire effettivamente l’esecuzione del programma in primo luogo se non hanno accesso.

Credo che alcune delle funzionalità CAS potrebbero non essere presenti in C # 4.0 da quello che ho sentito, non sono sicuro se questo potrebbe essere un problema o meno.

Non è stato ansible ottenere GetAccessControl () per generare un’eccezione su Windows 7 come consigliato nella risposta accettata.

Ho finito per usare una variazione della risposta di 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; } 

Spero che questo ti aiuti.

Ho affrontato lo stesso problema: come verificare se posso leggere / scrivere in una particolare directory. Ho finito con la soluzione facile per … testarlo davvero. Ecco la mia soluzione semplice ma efficace.

  class Program { ///  /// Tests if can read files and if any are present ///  ///  ///  private genericResponse check_canRead(string 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(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 } 

Spero che sia d’aiuto !