it-swarm.com.de

Wie prüft man, ob Berechtigungen zum Schreiben in ein Verzeichnis oder eine Datei vorhanden sind?

Ich habe ein Programm, das einige Daten mit einer Methode wie der folgenden in eine Datei schreibt.


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


     }
}

Beim Ausführen des Programms erhalte ich eine Fehlermeldung:

Nicht behandelte Ausnahme: System.UnauthorizedAccessException: Der Zugriff auf den Pfad 'mypath' wird verweigert. bei System.IO .__ Error.WinIOError (Int32 errorCode, String maybeFullPath) bei System.IO.FileStream.Init (String-Pfad, FileMode-Modus, FileAccess-Zugriff, NT32-Rechte, Boolean useRights, FileShare-Freigabe, Int32 bufferSize, FileOptions ptions, SECURITY_ATTRIBUTES secAttrs , String msgPath, Boolean bFromProxy) bei System.IO.FileStream..ctor (String-Pfad, FileMode-Modus, FileAccess-Zugriff FileShare-Freigabe, Int32 bufferSize, FileOptions-Optionen, String msgPath, Boolea bFromProxy)

Frage: Welchen Code benötige ich, um dies abzufangen und wie kann ich den Zugriff gewähren?

59
18hrs

UPDATE:

Der Code wurde basierend auf diese Antwort geändert, um veraltete Methoden loszuwerden.

Sie können den Sicherheitsnamespace verwenden, um Folgendes zu überprüfen:

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
    }

}

Soweit Sie diese Erlaubnis erhalten, müssen Sie den Benutzer bitten, dies irgendwie für Sie zu tun. Wenn Sie dies programmatisch tun könnten, wären wir alle in Schwierigkeiten;)

65
Josh

Wenn Ihr Code Folgendes ausführt:

  1. Überprüft, ob der aktuelle Benutzer die Berechtigung hat, etwas zu tun.
  2. Führt die Aktion aus, für die die Berechtigungen in 1 eingecheckt werden müssen.

Sie laufen Gefahr, dass sich die Berechtigungen zwischen 1 und 2 ändern, da Sie nicht vorhersagen können, was sonst zur Laufzeit auf dem System passieren wird. Daher sollte Ihr Code die Situation behandeln, in der eine nauthorisedAccessException ausgelöst wird, selbst wenn Sie zuvor Berechtigungen überprüft haben.

Beachten Sie, dass die Klasse SecurityManager zum Überprüfen von CAS-Berechtigungen verwendet wird und nicht beim Betriebssystem überprüft, ob der aktuelle Benutzer Schreibzugriff auf den angegebenen Speicherort hat (über ACLs und ACEs). Daher gibt IsGranted für lokal ausgeführte Anwendungen immer true zurück.

Beispiel (abgeleitet von Joshs Beispiel ):

//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.
}

Es ist knifflig und nicht empfehlenswert , die effektiven Berechtigungen aus dem Ordner basierend auf den unformatierten ACLs (die alle über - verfügbar sind) zu berechnen. System.Security.AccessControl Klassen). Andere Antworten zu Stack Overflow und dem weiteren Web empfehlen, die Aktion auszuführen, um zu ermitteln, ob Berechtigungen zulässig sind. This post fasst zusammen, was für die Implementierung der Berechtigungsberechnung erforderlich ist, und sollte ausreichen, um Sie davon abzuhalten.

30
Iain

Es ist eine feste Version von MaxOvrdrvs 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;
}
9
xmen

Entschuldigung, aber keine der vorherigen Lösungen hat mir geholfen. Ich muss beide Seiten überprüfen: SecurityManager und SO Berechtigungen. Ich habe viel gelernt mit Josh Code und mit iain Antwort, aber ich fürchte, ich muss Rakesh Code verwenden (auch dank ihm) ) Nur ein Fehler: Ich habe festgestellt, dass er nur auf Zulassen und nicht auf Verweigern von Berechtigungen prüft.

        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
Pablonete

Da dies nicht geschlossen ist, möchte ich einen neuen Eintrag für alle einreichen, die auf der Suche nach einer ordnungsgemäßen Funktionsweise sind ... mit einer Zusammenführung der hier gefundenen Informationen sowie mit DirectoryServices, um den Code selbst zu debuggen und die zu finden Den richtigen Code zu verwenden, hier ist, was ich gefunden habe, das für mich in jeder Situation funktioniert. Beachten Sie, dass meine Lösung das DirectoryInfo-Objekt erweitert.

    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
MaxOvrdrv

Nichts davon hat bei mir funktioniert. Sie kehren als wahr zurück, auch wenn sie es nicht sind. Das Problem ist, dass Sie die verfügbare Berechtigung gegen die aktuellen Prozessbenutzerrechte testen müssen. Bei diesem Test werden die Dateierstellungsrechte geprüft. Ändern Sie einfach die FileSystemRights-Klausel in 'Write', um den Schreibzugriff zu testen.

/// <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
JGU

Sie können versuchen, den folgenden Codeblock zu verwenden, um zu überprüfen, ob das Verzeichnis über Schreibzugriff verfügt.

Es überprüft die 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                 
           }
2
RockWorld

Wow ... in diesem Thread gibt es eine Menge Sicherheitscode auf niedriger Ebene, von denen die meisten auch bei mir nicht funktionierten, obwohl ich dabei viel gelernt habe. Eine Sache, die ich gelernt habe, ist, dass der größte Teil dieses Codes nicht auf Anwendungen ausgerichtet ist, die nach Benutzerzugriffsrechten suchen - es ist für Administratoren gedacht, die Rechte programmgesteuert ändern möchten, was - wie bereits erwähnt - keine gute Sache. Als Entwickler kann ich den "einfachen Ausweg" nicht nutzen, indem ich als Administrator ausgeführt werde. Ich bin weder einer auf dem Computer, auf dem der Code ausgeführt wird, noch meine Benutzer. So clever diese Lösungen sind - Sie sind nicht für meine Situation und wahrscheinlich auch nicht für die meisten einfachen Entwickler.

Wie die meisten Plakate dieser Art von Frage - ich hatte anfangs auch das Gefühl, dass es "hackey" ist - habe ich mich inzwischen dazu entschlossen, es zu versuchen und die mögliche Ausnahme genau erklären zu lassen, welche Rechte der Benutzer hat - weil Die Informationen, die ich erhielt, sagten mir nicht, was die Rechte tatsächlich waren. Der Code unten - hat.

  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

Funktion beenden

0
jinzai