检查.NET中的目录和文件写入权限

时间:2009-08-15 10:40:41

标签: c# .net winforms directory file-permissions

在我的.NET 2.0应用程序中,我需要检查是否有足够的权限来创建和写入目录的文件。为此,我有以下函数尝试创建一个文件并向其写入一个字节,然后删除自己以测试权限是否存在。

我认为检查的最佳方法是实际尝试并执行此操作,捕获发生的任何异常。虽然我对一般的异常捕获并不是特别满意,所以有更好的或者更可接受的方法吗?

private const string TEMP_FILE = "\\tempFile.tmp";

/// <summary>
/// Checks the ability to create and write to a file in the supplied directory.
/// </summary>
/// <param name="directory">String representing the directory path to check.</param>
/// <returns>True if successful; otherwise false.</returns>
private static bool CheckDirectoryAccess(string directory)
{
    bool success = false;
    string fullPath = directory + TEMP_FILE;

    if (Directory.Exists(directory))
    {
        try
        {
            using (FileStream fs = new FileStream(fullPath, FileMode.CreateNew, 
                                                            FileAccess.Write))
            {
                fs.WriteByte(0xff);
            }

            if (File.Exists(fullPath))
            {
                File.Delete(fullPath);
                success = true;
            }
        }
        catch (Exception)
        {
            success = false;
        }
    }

9 个答案:

答案 0 :(得分:46)

Directory.GetAcessControl(path)可以满足您的要求。

public static bool HasWritePermissionOnDir(string path)
{
    var writeAllow = false;
    var writeDeny = false;
    var accessControlList = Directory.GetAccessControl(path);
    if (accessControlList == null)
        return false;
    var accessRules = accessControlList.GetAccessRules(true, true, 
                                typeof(System.Security.Principal.SecurityIdentifier));
    if (accessRules ==null)
        return false;

    foreach (FileSystemAccessRule rule in accessRules)
    {
        if ((FileSystemRights.Write & rule.FileSystemRights) != FileSystemRights.Write) 
            continue;

        if (rule.AccessControlType == AccessControlType.Allow)
            writeAllow = true;
        else if (rule.AccessControlType == AccessControlType.Deny)
            writeDeny = true;
    }

    return writeAllow && !writeDeny;
}

(FileSystemRights.Write & rights) == FileSystemRights.Write正在使用名为“Flags”的东西,如果你不知道它应该是什么,你应该真正阅读:)

答案 1 :(得分:32)

Deny优先于Allow。本地规则优先于继承的规则。我已经看到了很多解决方案(包括这里显示的一些答案),但是它们都没有考虑规则是否继承。因此,我建议采用以下方法来考虑规则继承(整齐地包装到类中):

public class CurrentUserSecurity
{
    WindowsIdentity _currentUser;
    WindowsPrincipal _currentPrincipal;

    public CurrentUserSecurity()
    {
        _currentUser = WindowsIdentity.GetCurrent();
        _currentPrincipal = new WindowsPrincipal(_currentUser);
    }

    public bool HasAccess(DirectoryInfo directory, FileSystemRights right)
    {
        // Get the collection of authorization rules that apply to the directory.
        AuthorizationRuleCollection acl = directory.GetAccessControl()
            .GetAccessRules(true, true, typeof(SecurityIdentifier));
        return HasFileOrDirectoryAccess(right, acl);
    }

    public bool HasAccess(FileInfo file, FileSystemRights right)
    {
        // Get the collection of authorization rules that apply to the file.
        AuthorizationRuleCollection acl = file.GetAccessControl()
            .GetAccessRules(true, true, typeof(SecurityIdentifier));
        return HasFileOrDirectoryAccess(right, acl);
    }

    private bool HasFileOrDirectoryAccess(FileSystemRights right,
                                          AuthorizationRuleCollection acl)
    {
        bool allow = false;
        bool inheritedAllow = false;
        bool inheritedDeny = false;

        for (int i = 0; i < acl.Count; i++) {
            var currentRule = (FileSystemAccessRule)acl[i];
            // If the current rule applies to the current user.
            if (_currentUser.User.Equals(currentRule.IdentityReference) ||
                _currentPrincipal.IsInRole(
                                (SecurityIdentifier)currentRule.IdentityReference)) {

                if (currentRule.AccessControlType.Equals(AccessControlType.Deny)) {
                    if ((currentRule.FileSystemRights & right) == right) {
                        if (currentRule.IsInherited) {
                            inheritedDeny = true;
                        } else { // Non inherited "deny" takes overall precedence.
                            return false;
                        }
                    }
                } else if (currentRule.AccessControlType
                                                  .Equals(AccessControlType.Allow)) {
                    if ((currentRule.FileSystemRights & right) == right) {
                        if (currentRule.IsInherited) {
                            inheritedAllow = true;
                        } else {
                            allow = true;
                        }
                    }
                }
            }
        }

        if (allow) { // Non inherited "allow" takes precedence over inherited rules.
            return true;
        }
        return inheritedAllow && !inheritedDeny;
    }
}

但是,我的经验是,这并不总是适用于远程计算机,因为您无法始终查询那里的文件访问权限。在这种情况下的解决方案是尝试;甚至可能只是尝试创建一个临时文件,如果您需要在使用“真实”文件之前知道访问权限。

答案 2 :(得分:21)

RichardJason的答案是正确的方向。但是,对于运行代码的用户标识,您应该做的是computing the effective permissions。例如,上述示例都没有正确地考虑组成员身份。

我非常确定Keith Brown有一些代码可以在wiki versionThe .NET Developers Guide to Windows Security(此时离线)中执行此操作。在他的Programming Windows Security书中也对此进行了详细讨论。

计算有效权限不适合胆小的人,而您的代码尝试创建文件并捕获抛出的安全异常可能是阻力最小的路径。

答案 3 :(得分:18)

Kev对此问题的接受答案实际上并没有给出任何代码,只是指向我无法访问的其他资源。所以这是我对该功能的最佳尝试。它实际上会检查它正在查看的权限是否为“写入”权限,并且当前用户属于相应的组。

关于网络路径或其他什么可能不完整,但它足以满足我的目的,检查“Program Files”下的本地配置文件是否可写:

using System.Security.Principal;
using System.Security.AccessControl;

private static bool HasWritePermission(string FilePath)
{
    try
    {
        FileSystemSecurity security;
        if (File.Exists(FilePath))
        {
            security = File.GetAccessControl(FilePath);
        }
        else
        {
            security = Directory.GetAccessControl(Path.GetDirectoryName(FilePath));
        }
        var rules = security.GetAccessRules(true, true, typeof(NTAccount));

        var currentuser = new WindowsPrincipal(WindowsIdentity.GetCurrent());
        bool result = false;
        foreach (FileSystemAccessRule rule in rules)
        {
            if (0 == (rule.FileSystemRights &
                (FileSystemRights.WriteData | FileSystemRights.Write)))
            {
                continue;
            }

            if (rule.IdentityReference.Value.StartsWith("S-1-"))
            {
                var sid = new SecurityIdentifier(rule.IdentityReference.Value);
                if (!currentuser.IsInRole(sid))
                {
                    continue;
                }
            }
            else
            {
                if (!currentuser.IsInRole(rule.IdentityReference.Value))
                {
                    continue;
                }
            }

            if (rule.AccessControlType == AccessControlType.Deny)
                return false;
            if (rule.AccessControlType == AccessControlType.Allow)
                result = true;
        }
        return result;
    }
    catch
    {
        return false;
    }
}

答案 4 :(得分:5)

IMO,您需要像往常一样使用这些目录,但不是在使用前检查权限,而是提供正确的方法来处理UnauthorizedAccessException并做出相应的反应。这种方法更容易,更不容易出错。

答案 5 :(得分:3)

尝试使用我刚制作的C#片段:

using System;
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string directory = @"C:\downloads";

            DirectoryInfo di = new DirectoryInfo(directory);

            DirectorySecurity ds = di.GetAccessControl();

            foreach (AccessRule rule in ds.GetAccessRules(true, true, typeof(NTAccount)))
            {
                Console.WriteLine("Identity = {0}; Access = {1}", 
                              rule.IdentityReference.Value, rule.AccessControlType);
            }
        }
    }
}

here's您还可以查看参考文献。我的代码可能会让您了解在尝试写入目录之前如何检查权限。

答案 6 :(得分:1)

Since the static method 'GetAccessControl' seems to be missing from the present version of .Net core/Standard我不得不修改@Bryce Wagner的答案(我继续使用更现代的语法):

public static class PermissionHelper
{
  public static bool? CurrentUserHasWritePermission(string filePath)

     => new WindowsPrincipal(WindowsIdentity.GetCurrent())
        .SelectWritePermissions(filePath)
        .FirstOrDefault();


  private static IEnumerable<bool?> SelectWritePermissions(this WindowsPrincipal user, string filePath)
     => from rule in filePath
                    .GetFileSystemSecurity()
                    .GetAccessRules(true, true, typeof(NTAccount))
                    .Cast<FileSystemAccessRule>()
        let right = user.HasRightSafe(rule)
        where right.HasValue
        // Deny takes precedence over allow
        orderby right.Value == false descending
        select right;


  private static bool? HasRightSafe(this WindowsPrincipal user, FileSystemAccessRule rule)
  {
     try
     {
        return user.HasRight(rule);
     }
     catch
     {
        return null;
     }
  }

  private static bool? HasRight(this WindowsPrincipal user,FileSystemAccessRule rule )
     => rule switch
     {
        { FileSystemRights: FileSystemRights fileSystemRights } when (fileSystemRights &
                                                                      (FileSystemRights.WriteData | FileSystemRights.Write)) == 0 => null,
        { IdentityReference: { Value: string value } } when value.StartsWith("S-1-") &&
                                                            !user.IsInRole(new SecurityIdentifier(rule.IdentityReference.Value)) => null,
        { IdentityReference: { Value: string value } } when value.StartsWith("S-1-") == false &&
                                                            !user.IsInRole(rule.IdentityReference.Value) => null,
        { AccessControlType: AccessControlType.Deny } => false,
        { AccessControlType: AccessControlType.Allow } => true,
        _ => null
     };


  private static FileSystemSecurity GetFileSystemSecurity(this string filePath)
    => new FileInfo(filePath) switch
    {
       { Exists: true } fileInfo => fileInfo.GetAccessControl(),
       { Exists: false } fileInfo => (FileSystemSecurity)fileInfo.Directory.GetAccessControl(),
       _ => throw new Exception($"Check the file path, {filePath}: something's wrong with it.")
    };
}

答案 7 :(得分:0)

根据这个链接: http://www.authorcode.com/how-to-check-file-permission-to-write-in-c/

使用现有的类SecurityManager

更容易
package scattergraph;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

/**
 *
 * @author scott
 */
public class ScatterGraph extends JPanel {

    private List<Double> scores;
    private int padding = 20;
    private int labelPadding = 12;
    private int numberYDivisions = 6;
    private int pointWidth = 10;
    private Color gridColor = new Color(200, 200, 200, 200);
    private Color pointColor = new Color(255, 0, 255);
    private Color lineColor = new Color(255, 255, 253);
    private static final Stroke GRAPH_STROKE = new BasicStroke(2f);

    public ScatterGraph(List<Double> scores){
        this.scores = scores;
    }

    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;

        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        double xScale = ((double) getWidth() - (3 * padding) - labelPadding) / (scores.size() - 1);
        double yScale = ((double) getHeight() - (2 * padding) - labelPadding) / (getMaxScore() - getMinScore());


    List<Point> graphPoints = new ArrayList<>();
    for(int i = 0; i < scores.size(); i++){

        int x1 = (int)(i * xScale + padding + labelPadding);
        int y1 = (int)((getMaxScore() - scores.get(i) * yScale) + padding);

        graphPoints.add(new Point(x1, y1));
    }

    g2.setColor(Color.WHITE);
    g2.fillRect(padding + labelPadding, padding, getWidth() - (2*padding) - labelPadding, getHeight() - 2 * padding - labelPadding);
    g2.setColor(Color.BLUE);

    for(int i = 0; i < numberYDivisions + 1; i++){
        int x0 = padding + labelPadding;
        int x1 = pointWidth + padding + labelPadding;
        int y0 = getHeight() - ((i * (getHeight() - padding * 2 - labelPadding)) / numberYDivisions + padding + labelPadding);

        int y1 = y0;
        if(scores.size() > 0){
            g2.setColor(gridColor);
            g2.drawLine(padding + labelPadding + 1 + pointWidth, y0, getWidth() - padding, y1);
            g2.setColor(Color.BLACK);
            String yLabel = ((int) ((getMinScore() + (getMaxScore() - getMinScore()) * ((i * 8.0) / numberYDivisions)) * 100))/ 100.0 + "";

            FontMetrics metrics = g2.getFontMetrics();
            int labelWidth = metrics.stringWidth(yLabel);
            g2.drawString(yLabel, x0 - labelWidth - 6, y0 + (metrics.getHeight() / 2) - 3);

        }
            g2.drawLine(x0, y0, x1, y1);

    }

    for (int i = 0; i < scores.size(); i++){

        if (scores.size() > 1) {

            int x0 = i * (getWidth() - padding * 2 - labelPadding) / (scores.size() - 1) + padding + labelPadding;
            int x1 = x0;
            int y0 = getHeight() - padding - labelPadding;
            int y1 = y0 - pointWidth;
            if ((i % ((int) ((scores.size() / 8.0)) + 3)) == 0) {

                g2.setColor(gridColor);
                g2.drawLine(x0, getHeight() - padding - labelPadding - 1 - pointWidth, x1, padding);
                g2.setColor((Color.BLACK));
                String xLabel = i + "";
                FontMetrics metrics = g2.getFontMetrics();
                int labelWidth = metrics.stringWidth(xLabel);
                g2.drawString(xLabel, x0 - labelWidth / 2, y0 + metrics.getHeight() + 3);

            }

            g2.drawLine(x0, y0, x1, y1);



        }

    }

    g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, padding + labelPadding, padding);
    g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, getWidth() - padding, getHeight() - padding - labelPadding);

    Stroke oldStroke = g2.getStroke();
    g2.setColor(lineColor);
    g2.setStroke(GRAPH_STROKE);

    for (int i = 0; i < graphPoints.size() - 1; i++){
        int x1 = graphPoints.get(i).x;
        int y1 = graphPoints.get(i).y;
        int x2 = graphPoints.get(i + 1).x;
        int y2 = graphPoints.get(i + 1).y;
        g2.drawLine(x1, y1, x2, y2);

    }

    g2.setStroke(oldStroke);
    g2.setColor(pointColor);
    for (int i = 0; i < graphPoints.size(); i++){

           int x = graphPoints.get(i).x - pointWidth / 2;
           int y = graphPoints.get(i).y - pointWidth / 2;
           int ovalW = pointWidth;
           int ovalH = pointWidth;
           g2.fillOval(x, y, ovalW, ovalH);

    }


    }
    private double getMinScore(){
        double minScore = Double.MAX_VALUE;
        for(Double score: scores){
            minScore = Math.min(minScore, score);
        }
        return minScore;
    }


    private double getMaxScore(){
            double maxScore = Double.MIN_VALUE;
        for(Double score: scores){
            maxScore = Math.min(maxScore, score);
        }
        return maxScore;
    }


    public void setScores(List<Double> scores) {

          this.scores = scores;
          invalidate();
          this.repaint();

    }

        public List<Double> getScores() {
        return scores;
    }

    private static void createAndShowGui(){

        List<Double> scores = new ArrayList();
        Random random = new Random();

        int maxDataPoints = 20;
        int maxScore = 8;

        for(int i = 0 ; i < maxDataPoints; i++){

            scores.add((double)random.nextDouble() * maxScore);
            System.out.println("Score added");
        }


        ScatterGraph mainPanel = new ScatterGraph(scores);
        mainPanel.setPreferredSize(new Dimension(700,600));

        JFrame frame = new JFrame("My Scatter Graph");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable(){

            public void run(){
                createAndShowGui();
            }    

        });
    }

}

但似乎它已被废弃,建议改为使用PermissionSet。

string FileLocation = @"C:\test.txt";
FileIOPermission writePermission = new FileIOPermission(FileIOPermissionAccess.Write, FileLocation);
if (SecurityManager.IsGranted(writePermission))
{
  // you have permission
}
else
{
 // permission is required!
}

答案 8 :(得分:-1)

private static void GrantAccess(string file)
        {
            bool exists = System.IO.Directory.Exists(file);
            if (!exists)
            {
                DirectoryInfo di = System.IO.Directory.CreateDirectory(file);
                Console.WriteLine("The Folder is created Sucessfully");
            }
            else
            {
                Console.WriteLine("The Folder already exists");
            }
            DirectoryInfo dInfo = new DirectoryInfo(file);
            DirectorySecurity dSecurity = dInfo.GetAccessControl();
            dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
            dInfo.SetAccessControl(dSecurity);

        }