Comment vérifier les permissions pour écrire dans un répertoire ou un fichier?

j'ai obtenu un programme qui écrit des données à un dossier en utilisant une méthode comme celle ci-dessous.


public void ExportToFile(string filename)
{
     using(FileStream fstream = new FileStream(filename,FileMode.Create))
     using (TextWriter writer = new StreamWriter(fstream))
     {
         // try catch block for write permissions 
         writer.WriteLine(text);


     }
}

lors de l'exécution du programme j'obtiens une erreur:

Exception Non Gérée: System.Nonauthorizedaccessexception: L'accès au chemin 'mypath' est refusé. at System.IO._ _ Erreur.WinIOError(Int32 errorCode, String maybeFullPath)) at System.IO.FileStream.Init (chemin de Chaîne, Mode FileMode, accès FileAccess), nt32 des droits de l', Boolean useRights, FileShare share, Int32 bufferSize, FileOptions ptions, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) at System.IO.FileStream..ctor (chemin de Chaîne, Mode FileMode, accès FileAccess) FileShare part, bufferSize Int32, FileOptions options, d'une Chaîne msgPath, Boolea bFromProxy)

Question: de quel code ai-je besoin pour attraper ceci et comment accorder l'accès?

56
demandé sur Imran Ali Khan 2008-09-25 03:34:03

8 réponses

mise à jour:

a modifié le code basé sur cette réponse pour se débarrasser des méthodes obsolètes.

vous pouvez utiliser l'espace de noms de sécurité pour vérifier ceci:

public void ExportToFile(string filename)
{
    var permissionSet = new PermissionSet(PermissionState.None);    
    var writePermission = new FileIOPermission(FileIOPermissionAccess.Write, filename);
    permissionSet.AddPermission(writePermission);

    if (permissionSet.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet))
    {
        using (FileStream fstream = new FileStream(filename, FileMode.Create))
        using (TextWriter writer = new StreamWriter(fstream))
        {
            // try catch block for write permissions 
            writer.WriteLine("sometext");


        }
    }
    else
    {
        //perform some recovery action here
    }

}

Aussi loin que l'obtention des autorisations, vous allez avoir à demander à l'utilisateur de le faire pour vous en quelque sorte. Si vous pouviez par programmation à faire cela, alors nous serions tous dans la détresse ;)

63
répondu Josh 2017-05-23 12:10:21

quand votre code fait ce qui suit:

  1. vérifie que l'utilisateur actuel a la permission de faire quelque chose.
  2. effectue l'action qui nécessite les droits vérifiés dans 1.

vous courez le risque que les permissions changent entre 1 et 2 parce que vous ne pouvez pas prédire ce qui se passera d'autre sur le système à l'exécution. Par conséquent, votre code devrait gérer la situation où un Exception D'accès non autorisé est lancé même si vous avez déjà vérifié les permissions.

notez que la classe SecurityManager est utilisée pour vérifier les permissions CAS et ne vérifie pas réellement avec le système D'exploitation si l'utilisateur courant a accès en écriture à l'emplacement spécifié (via ACLs et ACEs). En tant que tel, IsGranted retournera toujours vrai pour localement applications en cours d'exécution.

exemple (dérivé de exemple de Josh ):

//1. Provide early notification that the user does not have permission to write.
FileIOPermission writePermission = new FileIOPermission(FileIOPermissionAccess.Write, filename);
if(!SecurityManager.IsGranted(writePermission))
{
    //No permission. 
    //Either throw an exception so this can be handled by a calling function
    //or inform the user that they do not have permission to write to the folder and return.
}

//2. Attempt the action but handle permission changes.
try
{
    using (FileStream fstream = new FileStream(filename, FileMode.Create))
    using (TextWriter writer = new StreamWriter(fstream))
    {
        writer.WriteLine("sometext");
    }
}
catch (UnauthorizedAccessException ex)
{
    //No permission. 
    //Either throw an exception so this can be handled by a calling function
    //or inform the user that they do not have permission to write to the folder and return.
}

c'est délicat et déconseillé essayer de calculer de façon programmatique les permissions effectives à partir du dossier basé sur les ACLs bruts (qui sont tout ce qui sont disponibles à travers le système .Sécurité.AccessControl classes). Autres réponses sur le débordement de pile et le Web plus large recommande d'essayer d'effectuer l'action pour savoir si la permission est autorisée. ce résume ce qui est nécessaire pour mettre en œuvre le calcul de permission et devrait être suffisant pour vous mettre à l'écart de faire cela.

30
répondu Iain 2017-05-23 11:46:23

de Ses une version fixe de MaxOvrdrv Code .

public static bool IsReadable(this DirectoryInfo di)
{
    AuthorizationRuleCollection rules;
    WindowsIdentity identity;
    try
    {
        rules = di.GetAccessControl().GetAccessRules(true, true, typeof(SecurityIdentifier));
        identity = WindowsIdentity.GetCurrent();
    }
    catch (UnauthorizedAccessException uae)
    {
        Debug.WriteLine(uae.ToString());
        return false;
    }

    bool isAllow = false;
    string userSID = identity.User.Value;

    foreach (FileSystemAccessRule rule in rules)
    {
        if (rule.IdentityReference.ToString() == userSID || identity.Groups.Contains(rule.IdentityReference))
        {
            if ((rule.FileSystemRights.HasFlag(FileSystemRights.Read) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.ReadAttributes) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.ReadData)) && rule.AccessControlType == AccessControlType.Deny)
                return false;
            else if ((rule.FileSystemRights.HasFlag(FileSystemRights.Read) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.ReadAttributes) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.ReadData)) && rule.AccessControlType == AccessControlType.Allow)
                isAllow = true;

        }
    }
    return isAllow;
}

public static bool IsWriteable(this DirectoryInfo me)
{
    AuthorizationRuleCollection rules;
    WindowsIdentity identity;
    try
    {
        rules = me.GetAccessControl().GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
        identity = WindowsIdentity.GetCurrent();
    }
    catch (UnauthorizedAccessException uae)
    {
        Debug.WriteLine(uae.ToString());
        return false;
    }

    bool isAllow = false;
    string userSID = identity.User.Value;

    foreach (FileSystemAccessRule rule in rules)
    {
        if (rule.IdentityReference.ToString() == userSID || identity.Groups.Contains(rule.IdentityReference))
        {
            if ((rule.FileSystemRights.HasFlag(FileSystemRights.Write) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.WriteAttributes) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.WriteData) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.CreateDirectories) ||
                rule.FileSystemRights.HasFlag(FileSystemRights.CreateFiles)) && rule.AccessControlType == AccessControlType.Deny)
                return false;
            else if ((rule.FileSystemRights.HasFlag(FileSystemRights.Write) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.WriteAttributes) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.WriteData) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.CreateDirectories) &&
                rule.FileSystemRights.HasFlag(FileSystemRights.CreateFiles)) && rule.AccessControlType == AccessControlType.Allow)
                isAllow = true;

        }
    }
    return isAllow;
}
7
répondu xmen 2017-05-23 11:54:20

désolé, mais aucune des solutions précédentes ne m'a aidé. Je dois vérifier les deux côtés: SecurityManager et donc les permissions. J'ai beaucoup appris avec Josh code et avec iain answer, mais je crains que je dois utiliser Rakesh code (également grâce à lui). Un seul bug: j'ai trouvé qu'il ne vérifie que les permissions Allow et pas les permissions Deny. Donc ma proposition est:

        string folder;
        AuthorizationRuleCollection rules;
        try {
            rules = Directory.GetAccessControl(folder)
                .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
        } catch(Exception ex) { //Posible UnauthorizedAccessException
            throw new Exception("No permission", ex);
        }

        var rulesCast = rules.Cast<FileSystemAccessRule>();
        if(rulesCast.Any(rule => rule.AccessControlType == AccessControlType.Deny)
            || !rulesCast.Any(rule => rule.AccessControlType == AccessControlType.Allow))
            throw new Exception("No permission");

        //Here I have permission, ole!
6
répondu Pablonete 2010-08-06 09:10:55

comme ceci n'est pas fermé, je voudrais soumettre une nouvelle entrée pour quiconque cherche à avoir quelque chose qui fonctionne correctement pour eux... en utilisant un amalgame de ce que j'ai trouvé ici, ainsi qu'en utilisant DirectoryServices pour déboguer le code lui-même et trouver le bon code à utiliser, voici ce que j'ai trouvé qui fonctionne pour moi dans chaque situation... notez que ma solution étend L'objet DirectoryInfo... :

    public static bool IsReadable(this DirectoryInfo me)
    {

        AuthorizationRuleCollection rules;
        WindowsIdentity identity;
        try
        {
            rules = me.GetAccessControl().GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
            identity = WindowsIdentity.GetCurrent();
        }
        catch (Exception ex)
        { //Posible UnauthorizedAccessException
            return false;
        }

        bool isAllow=false;
        string userSID = identity.User.Value;

        foreach (FileSystemAccessRule rule in rules)
        {
            if (rule.IdentityReference.ToString() == userSID || identity.Groups.Contains(rule.IdentityReference))
            {
                if ((rule.FileSystemRights.HasFlag(FileSystemRights.Read) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadAndExecute) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadData) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadExtendedAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadPermissions)) && rule.AccessControlType == AccessControlType.Deny)
                    return false;
                else if ((rule.FileSystemRights.HasFlag(FileSystemRights.Read) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadAndExecute) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadData) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadExtendedAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.ReadPermissions)) && rule.AccessControlType == AccessControlType.Allow)
                    isAllow = true;
            }
        }

        return isAllow;
    }

    public static bool IsWriteable(this DirectoryInfo me)
    {
        AuthorizationRuleCollection rules;
        WindowsIdentity identity;
        try
        {
            rules = me.GetAccessControl().GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
            identity = WindowsIdentity.GetCurrent();
        }
        catch (Exception ex)
        { //Posible UnauthorizedAccessException
            return false;
        }

        bool isAllow = false;
        string userSID = identity.User.Value;

        foreach (FileSystemAccessRule rule in rules)
        {
            if (rule.IdentityReference.ToString() == userSID || identity.Groups.Contains(rule.IdentityReference))
            {
                if ((rule.FileSystemRights.HasFlag(FileSystemRights.Write) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteData) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteExtendedAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.CreateDirectories) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.CreateFiles)) && rule.AccessControlType == AccessControlType.Deny)
                    return false;
                else if ((rule.FileSystemRights.HasFlag(FileSystemRights.Write) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteData) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.WriteExtendedAttributes) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.CreateDirectories) ||
                    rule.FileSystemRights.HasFlag(FileSystemRights.CreateFiles)) && rule.AccessControlType == AccessControlType.Allow)
                    isAllow = true;
            }
        }

        return me.IsReadable() && isAllow;
    }
4
répondu MaxOvrdrv 2014-08-15 19:49:47

rien de tout cela ne marchait pour moi.. ils reviennent comme vrais, même quand ils ne le sont pas. Le problème est que vous devez tester la permission disponible par rapport aux droits de l'utilisateur du processus en cours, ceci teste les droits de création de fichiers, il suffit de changer la clause FileSystemRights en "écriture" pour tester l'accès en écriture..

/// <summary>
/// Test a directory for create file access permissions
/// </summary>
/// <param name="DirectoryPath">Full directory path</param>
/// <returns>State [bool]</returns>
public static bool DirectoryCanCreate(string DirectoryPath)
{
    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 ((FileSystemRights.CreateFiles & rule.FileSystemRights) == FileSystemRights.CreateFiles)
                {
                    if (rule.AccessControlType == AccessControlType.Allow)
                        return true;
                }
            }
        }
    }
    catch {}
    return false;
}
3
répondu JGU 2014-02-23 20:55:53

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                 
           }
2
répondu RockWorld 2009-11-26 06:19:11

Wow...il y a beaucoup de code de sécurité de bas niveau dans ce fil -- la plupart d'entre eux n'ont pas fonctionné pour moi non plus -- bien que j'ai beaucoup appris au cours du processus. Une chose que j'ai apprise, c'est que la plupart de ce code n'est pas adapté aux applications cherchant des droits d'accès par utilisateur -- c'est pour les administrateurs qui veulent modifier les droits par programme, ce qui -- comme on l'a souligné -- est et non une bonne chose. En tant que développeur, Je ne peux pas utiliser" easy way out " -- en tournant comme Administrateur -- qui -- je ne suis pas sur la machine qui exécute le code, ni mes utilisateurs -- donc, aussi astucieux que soient ces solutions -- ils ne sont pas pour ma situation, et probablement pas pour la plupart des développeurs de fichiers de base, non plus.

comme la plupart des posters de ce type de question -- j'ai d'abord senti qu'il était "hackey", aussi -- j'ai depuis décidé qu'il est parfaitement correct de l'essayer et laisser l'exception possible vous dire exactement ce que les droits de l'utilisateur sont -- parce que le les informations que j'ai reçues ne m'ont pas indiqué quels étaient les droits. Le code ci-dessous -- ne.

  Private Function CheckUserAccessLevel(folder As String) As Boolean
Try
  Dim newDir As String = String.Format("{0}{1}{2}",
                                       folder,
                                       If(folder.EndsWith("\"),
                                          "",
                                          "\"),
                                       "LookWhatICanDo")
  Dim lookWhatICanDo = Directory.CreateDirectory(newDir)

  Directory.Delete(newDir)
  Return True

Catch ex As Exception
  Return False
End Try

Fin De La Fonction

0
répondu jinzai 2017-09-27 15:58:43