首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 設定與讀取 NTFS 目錄權限 (ACL) 完整實作

     編輯:關於C#

控制 NTFS 目錄存取權限 (ACL) 是檔案伺服器、多使用者應用、安全性合規常見需求。本文完整示範 C# 使用 `System.Security.AccessControl` 新增、移除、讀取、稽核目錄權限,含繼承旗標、傳播旗標、存取規則類型完整解析。

核心類別架構

| 類別 | 用途 | |------|------| | `DirectorySecurity` | 目錄安全性描述元 (DACL + SACL) | | `FileSystemAccessRule` | 存取規則 (允許/拒絕、權限、身分、繼承) | | `FileSystemAuditRule` | 稽核規則 (成功/失敗事件記錄) | | `FileSystemRights` | 權限旗標列舉 (Read, Write, Modify, FullControl 等) | | `InheritanceFlags` | 繼承範圍 (ContainerInherit, ObjectInherit, None) | | `PropagationFlags` | 傳播行為 (None, InheritOnly, NoPropagateInherit) | | `AccessControlType` | 規則類型 (Allow, Deny) | | `IdentityReference` | 身分參考 (User, Group, SID) |

新增目錄權限完整範例

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

public static class DirectoryAclManager
{
    /// 
    /// 為目錄新增使用者/群組存取權限
    /// 
    /// 目標目錄完整路徑
    /// 使用者/群組名稱 (如 "Users", "DOMAIN\\User", "Everyone")
    /// 權限字串: R=Read, W=Write, M=Modify, F=FullControl, C=ChangePermissions
    /// 繼承模式
    /// Allow/Deny
    public static void AddDirectoryAccessRule(
        string directoryPath,
        string identity,
        string rights,
        InheritanceFlags inheritance = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
        AccessControlType accessType = AccessControlType.Allow)
    {
        if (!Directory.Exists(directoryPath))
            throw new DirectoryNotFoundException($"目錄不存在:{directoryPath}");

        // 解析權限字串
        FileSystemRights fsRights = ParseRights(rights);

        // 取得現有安全性描述元
        DirectoryInfo dirInfo = new DirectoryInfo(directoryPath);
        DirectorySecurity dirSecurity = dirInfo.GetAccessControl(AccessControlSections.Access);

        // 建立存取規則
        var rule = new FileSystemAccessRule(
            identity,
            fsRights,
            inheritance,
            PropagationFlags.None,
            accessType);

        // 新增規則 (不覆蓋既有)
        dirSecurity.AddAccessRule(rule);

        // 套用變更
        dirInfo.SetAccessControl(dirSecurity);
    }

    private static FileSystemRights ParseRights(string rights)
    {
        FileSystemRights result = 0;
        foreach (char c in rights.ToUpper())
        {
            result |= c switch
            {
                'R' => FileSystemRights.Read,
                'W' => FileSystemRights.Write,
                'M' => FileSystemRights.Modify,
                'F' => FileSystemRights.FullControl,
                'C' => FileSystemRights.ChangePermissions,
                'T' => FileSystemRights.TakeOwnership,
                'D' => FileSystemRights.Delete,
                'A' => FileSystemRights.AppendData,
                _ => 0
            };
        }
        return result;
    }
}

讀取並列舉目錄權限

public static void ListDirectoryPermissions(string directoryPath)
{
    if (!Directory.Exists(directoryPath))
    {
        Console.WriteLine("目錄不存在");
        return;
    }

    DirectorySecurity security = Directory.GetAccessControl(directoryPath, AccessControlSections.All);

    Console.WriteLine($"=== {directoryPath} 權限列表 ===");
    Console.WriteLine($"擁有者:{security.GetOwner(typeof(NTAccount))}");
    Console.WriteLine($"群組:{security.GetGroup(typeof(NTAccount))}");

    // DACL (存取規則)
    var accessRules = security.GetAccessRules(true, true, typeof(NTAccount));
    Console.WriteLine("\n--- 存取規則 (DACL) ---");
    foreach (FileSystemAccessRule rule in accessRules)
    {
        Console.WriteLine($"身分:{rule.IdentityReference.Value,-30} " +
            $"類型:{rule.AccessControlType,-5} " +
            $"權限:{rule.FileSystemRights,-20} " +
            $"繼承:{rule.InheritanceFlags,-25} " +
            $"傳播:{rule.PropagationFlags} " +
            $"{(rule.IsInherited ? "[繼承]" : "[明確]")}");
    }

    // SACL (稽核規則)
    var auditRules = security.GetAuditRules(true, true, typeof(NTAccount));
    Console.WriteLine("\n--- 稽核規則 (SACL) ---");
    foreach (FileSystemAuditRule rule in auditRules)
    {
        Console.WriteLine($"身分:{rule.IdentityReference.Value,-30} " +
            $"類型:{rule.AuditFlags,-15} " +
            $"繼承:{rule.InheritanceFlags} " +
            $"{(rule.IsInherited ? "[繼承]" : "[明確]")}");
    }
}

移除特定權限規則

public static void RemoveDirectoryAccessRule(
    string directoryPath,
    string identity,
    FileSystemRights rights,
    InheritanceFlags inheritance,
    AccessControlType accessType)
{
    DirectoryInfo dirInfo = new DirectoryInfo(directoryPath);
    DirectorySecurity dirSecurity = dirInfo.GetAccessControl(AccessControlSections.Access);

    var rule = new FileSystemAccessRule(identity, rights, inheritance, PropagationFlags.None, accessType);
    
    // 移除完全匹配的規則
    bool removed = dirSecurity.RemoveAccessRule(rule);
    // 或移除所有匹配身分的規則
    // bool removed = dirSecurity.PurgeAccessRules(new NTAccount(identity));

    if (removed)
    {
        dirInfo.SetAccessControl(dirSecurity);
        Console.WriteLine("規則已移除");
    }
    else
    {
        Console.WriteLine("找不到匹配的規則");
    }
}

繼承與傳播旗標詳細解析

| 組合 | 效果 | 適用場景 | |------|------|----------| | `ContainerInherit \| ObjectInherit` + `None` | 子資料夾**與**檔案繼承,自身也套用 | **最常用**:目錄完整權限控制 | | `ContainerInherit` + `InheritOnly` | 僅子資料夾繼承,**自身不套用** | 父目錄不需此權限,但希望子目錄擁有 | | `ObjectInherit` + `InheritOnly` | 僅檔案繼承,**自身不套用** | 僅控制檔案權限 | | `ContainerInherit \| ObjectInherit` + `NoPropagateInherit` | 子項繼承,但**孫項不再繼承** | 單層傳播控制 |

常見權限組合速查

| 需求 | 權限字串 | FileSystemRights 旗標 | |------|----------|----------------------| | 唯讀 | `R` | `Read` (含 ListDirectory, ReadData, ReadAttributes, ReadExtendedAttributes, ReadPermissions) | | 讀寫 | `RW` | `Read \| Write` | | 修改 (含刪除) | `RM` 或 `M` | `Modify` (含 Read, Write, Delete, Synchronize) | | 完全控制 | `F` | `FullControl` (所有權限) | | 僅建立檔案 | `A` | `AppendData` (含 CreateFiles) | | 僅建立資料夾 | `RW` + `ContainerInherit Only` | `CreateDirectories` (需特定旗標) | | 變更權限 | `C` | `ChangePermissions` | | 取得擁有權 | `T` | `TakeOwnership` |

進階:SID 直接操作 (避免名稱解析問題)

public static void AddRuleBySid(string directoryPath, string sidString, FileSystemRights rights)
{
    var sid = new SecurityIdentifier(sidString);
    var rule = new FileSystemAccessRule(sid, rights, 
        InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
        PropagationFlags.None, AccessControlType.Allow);
    
    var dirInfo = new DirectoryInfo(directoryPath);
    var security = dirInfo.GetAccessControl(AccessControlSections.Access);
    security.AddAccessRule(rule);
    dirInfo.SetAccessControl(security);
}

// 知名 SID
var everyoneSid = new SecurityIdentifier(WellKnownSidType.WorldSid, null); // S-1-1-0
var administratorsSid = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null); // S-1-5-32-544
var usersSid = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null); // S-1-5-32-545

注意事項與最佳實踐

| 項目 | 建議 | |------|------| | **執行權限** | 需管理員權限或目錄 `ChangePermissions`/`TakeOwnership` 權限 | | **繼承中斷** | `dirSecurity.SetAccessRuleProtection(true, false)` 切斷繼承 (保留既有規則) | | **規則順序** | Deny 規則優先於 Allow,`AddAccessRule` 會自動排序 | | **大量操作** | 批次修改時建議一次 `GetAccessControl`、多次 `Add/Remove`、最後 `SetAccessControl` | | **錯誤處理** | 捕獲 `UnauthorizedAccessException`、`PrivilegeNotHeldException`、`SystemException` | | **稽核啟用** | 本機安全性原則 → 物件存取稽核 → 成功/失敗,SACL 才會生效 |

測試範例

// 1. 給 Users 群組讀寫權限 (繼承至子項)
DirectoryAclManager.AddDirectoryAccessRule(@"D:\SharedData", "Users", "RW");

// 2. 給 Administrators 完全控制
DirectoryAclManager.AddDirectoryAccessRule(@"D:\SharedData", "Administrators", "F");

// 3. 列出權限
DirectoryAclManager.ListDirectoryPermissions(@"D:\SharedData");

// 4. 移除特定規則
DirectoryAclManager.RemoveDirectoryAccessRule(
    @"D:\SharedData", "Guest", FileSystemRights.FullControl,
    InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
    AccessControlType.Allow);

掌握 ACL 程式化操作,能建立自動化部署腳本、權限管理工具、合規稽核系統,確保檔案系統安全性策略精確落地。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved