Tengo que probar si un usuario puede escribir en una carpeta antes de intentar hacerlo.

He implementado el método siguiente (en C# 2.0) que intenta recuperar los permisos de seguridad de la carpeta utilizando Directorio.GetAccessControl() método.

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

Cuando yo estaba buscando en google cómo para la prueba de acceso de escritura nada de esto ocurrió y parecía muy complicado para realmente probar los permisos en Windows. Me preocupa que estoy simplificando las cosas, y que este método no es robusto, aunque no parece funcionar.

Mi método para probar si el usuario actual tiene acceso de escritura funciona correctamente?

  • Es no tener acceso a la ver los permisos en realidad la misma no está permitido escribir en él?
InformationsquelleAutor Chris B | 2009-09-11

18 Comentarios

  1. 59

    Que es una forma perfectamente válido para comprobar el acceso a la carpeta en C#. El único lugar en el que podría caer es que si usted necesita para llamar a esta en un bucle estrecho donde la sobrecarga de una excepción puede ser un problema.

    Ha habido otros similar preguntas formuladas anteriormente.

    • Curiosamente yo tenía una de esas otras preguntas se abra en otra pestaña, pero no había visto la respuesta acerca de la DirectorySecurity, me enseñan a leer todo las respuestas no sólo la aceptación de uno;-)
    • No es también caer cuando el uso a largo rutas de acceso en Windows?
    • Que no le dirá si usted tiene permiso de escritura, sólo le dirá si usted puede ver los permisos en esa carpeta o no. También usted podría ser capaz de escribir pero no ser capaces de buscar los permisos.
  2. 61

    Agradezco que este es un poco tarde en el día para este post, pero usted puede encontrar este fragmento de código útil.

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

    Gota que en una aplicación de Consola y ver si hace lo que usted necesita.

    • Justo en el blanco! Me ayuda mucho!
    • Puedo obtener una excepción en la llamada a la GetAccessControl pero mi software es realmente capaz de escribir en el directorio estoy mirando.. ?
    • qué excepción están recibiendo? La primera cosa que salta a la mente es, irónicamente, un problema de seguridad. La cuenta que se está ejecutando la aplicación como tiene permiso para obtener la información ACL?
    • Buen trabajo aquí. Esto no se acaba hasta la solución de mi problema, sin embargo. Si la aplicación se está ejecutando en un usuario que no tenga privilegios de escritura sobre la carpeta, GetAccessControl arrojará una excepción. Pero que me dio lo que yo neeeded, un simple try/catch!
    • Usted puede tener permisos de escritura en una carpeta sin tener acceso a los permisos de seguridad. Además, no parece que esto va a manejar el caso si usted es un miembro de un grupo como es la comprobación de que el nombre de la cuenta directamente.
    • que el primer punto es nuevo para mí, así que gracias. En cuanto al segundo punto, es cierto que este fragmento de cheques de la cuenta directamente, pero no hay nada que impida que poner esto en un método y pasando las variables como parámetros y, a continuación, la enumeración sobre el grupo de usuarios de pertenencia externamente y pasando esos detalles.
    • ¿Esto también comprobar los permisos heredados?
    • Usted necesita agregar un cheque por FileSystemAccessRule tipo. Si es una regla de rechazo, se le informe incorrectamente como de escritura.
    • Buen lugar y gracias. He actualizado el código para probar la regla de la AccessControlType para asegurarse de que el «WriteData» la configuración no es una regla de rechazo
    • Estoy tratando de usar este. Encontró otro problema. Si los derechos sólo son asignados a los grupos y no específicas de los usuarios, de forma incorrecta informe que no tiene acceso de escritura. Por ejemplo, el acceso de escritura otorgada a «usuarios Autenticados»
    • este fue un punto planteado por RandomEngy (ver arriba). No sólo la prueba de acceso para una determinada identidad y no de búsqueda de los grupos que la cuenta es un miembro de. Como se sugirió anteriormente, usted podría simplemente extraer este código en un método y pasa el nombre de la cuenta y el directorio como argumentos
    • no funciona si el directorio es un recurso compartido de red y el usuario tiene derechos a nivel local, pero no a través de la participación.
    • eso es cierto, pero eso es debido a que los permisos de recurso compartido son diferentes de los permisos de sistema de archivo. Esto va de acuerdo con los permisos del sistema de archivos, no de los permisos de uso compartido.
    • esto me da PrivilegeNotHeldException cuando se ejecuta con privilegios normal

  3. 58
    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;
        }
    }
    • Esta respuesta va a capturar todas las excepciones que podría ocurrir cuando se trata de escribir un archivo, no sólo el permiso de violaciones.
    • Casi bueno! pero, ¿cómo hacerlo sin crear un archivo real.. lo que si un archivo con el mismo nombre ya existe… buen intento, aunque 🙂
    • tempFileName = Ruta de acceso.GetRandomFileName();, evidentemente
    • esto responde exactamente a la pregunta «es que sea escribible», independientemente de la razón de la falla, sin embargo. Que más que responder a «porque no puedo escribir en el directorio». 🙂
    • Puedo obtener un falso positivo con este código. El Archivo.Crear() funciona bien (y sale un archivo temporal si cambia la última opción) aunque la ejecución de usuario no tiene permiso para escribir en esa carpeta. Realmente muy extraño pasó una hora tratando de averiguar por qué, pero estoy perplejo.
    • Usted puede tener acceso a Escribir en el archivo, pero no eliminar. Compruebe sus permisos de NTFS.
    • De todas las alternativas que me han tratado a continuación (y se hace referencia a los enlaces) – este es el único que funciona de forma fiable.
    • Por favor, tenga en cuenta que esta técnica cambia la «fecha de última modificación» del directorio.

  4. 20

    He probado la mayoría de estos, pero que dan falsos positivos, todos por la misma razón.. no es suficiente para probar el directorio de una autorización, usted tiene que comprobar que el usuario es un miembro de un grupo que tiene ese permiso. Para hacer esto usted obtener la identidad de los usuarios, y comprobar si es un miembro de un grupo que contiene el FileSystemAccessRule IdentityReference. He probado esto, funciona a la perfección..

        ///<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;
        }
    • Gracias John, tengo falsos positivos como bien hasta que he de utilizar su código para comprobar el grupo de usuario de nuevo la regla de IdentifyReference!
    • este debe marcar la respuesta correcta.
    • he tenido que añadir una comprobación adicional de la identidad.Propietario == regla.IdentityReference como había un usuario que da acceso, pero no en ninguno de los grupos, como un local dedicado en cuenta para los servicios de
    • AccessControlType negar tiene prioridad sobre permitir, así que para ser completamente exhaustivo de reglas que niegan el derecho de acceso debe ser marcada, y al comprobar negar tipos debe ser (AccessRight & rule.FileSystemRights) > 0 porque cualquier sub tipo de acceso denegado que es parte de AccessRight significa que usted no tiene que completo el acceso a AccessRight
  5. 13

    Por ejemplo, para todos los usuarios (Builtin\Usuarios), este método funciona bien – disfrutar.

    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;
        }
    }
  6. 11

    Mi humilde opinión, la única 100% confiable manera de probar si se puede escribir en un directorio es escribir para él y, finalmente, la captura de excepciones.

  7. 8

    Intente esto:

    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");
    }
    • Si no me equivoco, esto es cerca, pero no del todo … esto pasa por alto el hecho de que fsAccessRule.AccessControlType podría ser AccessControlType.Deny.
    • Este estaba trabajando para mí en mi Win7 dev máquina, pero no en Win10 (ambos con un tester y mi propia máquina de prueba). las unidades ssd de modificación (ver más abajo) aparece solucionarlo.
  8. 6

    El código obtiene el DirectorySecurity para un determinado directorio, y maneja una excepción (debido a su no tener acceso a la información de seguridad) correctamente. Sin embargo, en la muestra que en realidad no interrogar al objeto devuelto a ver lo que el acceso está permitido – y creo que usted necesita para agregar esto.

    • +1 – me encontré con este problema donde una excepción no fue arrojado al llamar GetAccessControl pero me no autorizado excepción al intentar escribir en ese mismo directorio.
  9. 6

    Aquí es una versión modificada de CsabaS la respuesta, lo que representa para denegar explícito de las reglas de acceso. La función pasa a través de todos FileSystemAccessRules para un directorio, y comprueba si el usuario actual es el papel que tiene acceso a un directorio. Si no estas funciones se encuentran o si el usuario está en un papel con el acceso denegado, la función devuelve false. Para comprobar los derechos de lectura, pasar FileSystemRights.Leer a la función; por derechos de escritura, pasar FileSystemRights.Escribir. Si desea comprobar si un usuario arbitrario del derecho y no de la actual, de sustituir el currentUser WindowsIdentity para la deseada WindowsIdentity. También me gustaría aconsejar en contra de confiar en funciones como éste para determinar si el usuario puede utilizar de forma segura el directorio. Este respuesta perfectamente explica por qué.

        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;
        }
    • Csaba del código estaba fallando para mí en Windows 10 (pero bien en mi Win7 dev máquina). Lo anterior parece solucionar el problema.
  10. 5

    He utilizado la misma función para comprobar si el archivo 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;
            }
        }
    • Devuelve true si no se tiene permiso de Escritura, pero tiene acceso de Lectura.
  11. 3

    Puede intentar siguiente bloque de código para comprobar si el directorio es tener Acceso de Escritura.
    Comprueba la 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 
    }
    • Esto es lo que mi código ya no
  12. 2

    Tiene un potencial de condición de carrera en el código–¿qué sucede si el usuario tiene permisos para escribir en la carpeta cuando se compruebe, pero antes de que el usuario escribe en la carpeta de este permiso se retira? La escritura, se produce una excepción que usted tendrá que detectar y controlar. Para la comprobación inicial es inútil. Usted puede ser que también acaba de hacer el escribir y manejar las excepciones. Este es el patrón estándar para su situación.

  13. 2

    Soluciones anteriores son buenos, pero para mí, me parece que este código simple y viable.
    Basta con crear un archivo temporal. Si el archivo es creado, su media usuario tiene acceso de escritura.

            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;
            }
    • Bueno! Una cosa es la que el usuario puede tener Create el permiso, pero no Delete en cuyo caso se devuelve false, aunque el usuario no tiene permiso de escritura.
    • La mayoría de la respuesta adecuada para la codificación 🙂 yo también uso este solo, sin embargo, cuando hay grandes solicitudes simultáneas a continuación, tanto de lectura/escritura puede ralentizar el rendimiento, por lo que en esos casos se puede usar accesscontrol metodología como se da en otras respuestas.
  14. 1

    Simplemente tratando de tener acceso al archivo en cuestión no es necesariamente suficiente. La prueba se ejecutará con los permisos del usuario que ejecuta el programa – Que no es necesariamente el de los permisos de usuario que desea probar en contra.

  15. 0

    Estoy de acuerdo con la Ceniza, que debe estar bien. Alternativamente, usted podría utilizar declarativa CAS y de esta manera evitar que el programa se ejecute en primer lugar, si no tiene acceso.

    Creo que algunos de los CAS características pueden no estar presentes en C# 4.0 de lo que he oído, no sé si esto podría ser un problema o no.

  16. 0

    Yo no podía conseguir GetAccessControl() para lanzar una excepción en Windows 7, como se recomienda en la aceptó respuesta.

    Terminé usando una variación de sdds del respuesta:

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

    Espero que esto ayude.

  17. 0

    Yo enfrentan el mismo problema: cómo comprobar si soy capaz de leer/escribir en un directorio en particular. Terminé con la solución fácil…en realidad la prueba.
    Aquí es mi simple, aunque eficaz solución.

     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
    }

    Espero que ayude !

Dejar respuesta

Please enter your comment!
Please enter your name here