You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET是否有获取用户有效文件夹权限的API?Windows API能否通过PInvoke调用?

在.NET中获取用户有效文件夹权限的Windows API(PInvoke方式)

你说得对,用DirectorySecurity.GetAccessRules()确实得自己手动梳理用户自身权限、所属组权限还有继承来的权限,合并起来特别麻烦。其实Windows原生API里有专门的函数可以直接帮你算出用户对某个文件夹的有效权限,不用自己折腾权限合并逻辑,咱们可以通过PInvoke来调用这些API。

核心Windows API介绍

最常用的两个关键函数是:

  • AccessCheck:这是核心函数,它会自动处理组权限、继承权限、拒绝权限的优先级等所有逻辑,直接返回用户对目标对象的最终有效权限集。
  • GetNamedSecurityInfo:用来获取目标文件夹的安全描述符(包含DACL,也就是自主访问控制列表),作为AccessCheck的输入参数。

PInvoke代码示例

下面是一个完整的.NET代码示例,演示如何调用这些API来获取当前用户对指定文件夹的有效权限:

首先,定义必要的PInvoke结构体和函数声明:

using System;
using System.Runtime.InteropServices;
using System.Security.Principal;

public static class EffectivePermissionsHelper
{
    // 权限常量,对应FileSystemRights
    private const uint FILE_READ_DATA = 0x0001;
    private const uint FILE_WRITE_DATA = 0x0002;
    private const uint FILE_APPEND_DATA = 0x0004;
    private const uint FILE_READ_EA = 0x0008;
    private const uint FILE_WRITE_EA = 0x0010;
    private const uint FILE_EXECUTE = 0x0020;
    private const uint FILE_DELETE_CHILD = 0x0040;
    private const uint FILE_READ_ATTRIBUTES = 0x0080;
    private const uint FILE_WRITE_ATTRIBUTES = 0x0100;
    private const uint DELETE = 0x00010000;
    private const uint READ_CONTROL = 0x00020000;
    private const uint WRITE_DAC = 0x00040000;
    private const uint WRITE_OWNER = 0x00080000;
    private const uint SYNCHRONIZE = 0x00100000;

    [StructLayout(LayoutKind.Sequential)]
    private struct SID_AND_ATTRIBUTES
    {
        public IntPtr Sid;
        public uint Attributes;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct TOKEN_USER
    {
        public SID_AND_ATTRIBUTES User;
    }

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool GetNamedSecurityInfo(
        string pObjectName,
        int ObjectType,
        uint SecurityInfo,
        out IntPtr ppsidOwner,
        out IntPtr ppsidGroup,
        out IntPtr ppDacl,
        out IntPtr ppSacl,
        out IntPtr ppSecurityDescriptor);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool OpenProcessToken(
        IntPtr ProcessHandle,
        uint DesiredAccess,
        out IntPtr TokenHandle);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool GetTokenInformation(
        IntPtr TokenHandle,
        int TokenInformationClass,
        IntPtr TokenInformation,
        uint TokenInformationLength,
        out uint ReturnLength);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool AccessCheck(
        IntPtr pSecurityDescriptor,
        IntPtr ClientToken,
        uint DesiredAccess,
        IntPtr PrivilegeSet,
        out uint PrivilegeSetLength,
        out uint GrantedAccess,
        out uint AccessStatus,
        IntPtr AuditInfo);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr GetCurrentProcess();

    [DllImport("advapi32.dll")]
    private static extern bool IsValidSid(IntPtr pSid);

    [DllImport("kernel32.dll")]
    private static extern void LocalFree(IntPtr hMem);

    private const int SE_FILE_OBJECT = 1;
    private const uint DACL_SECURITY_INFORMATION = 0x00000004;
    private const int TokenUser = 1;
    private const uint TOKEN_QUERY = 0x0008;

然后,实现获取有效权限的方法:

public static System.Security.AccessControl.FileSystemRights GetEffectiveFolderPermissions(string folderPath)
    {
        // 1. 获取当前进程的访问令牌
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, out IntPtr tokenHandle))
            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());

        try
        {
            // 2. 获取令牌中的用户SID
            uint bufferSize = 0;
            GetTokenInformation(tokenHandle, TokenUser, IntPtr.Zero, 0, out bufferSize);
            IntPtr tokenInfoPtr = Marshal.AllocHGlobal((int)bufferSize);
            try
            {
                if (!GetTokenInformation(tokenHandle, TokenUser, tokenInfoPtr, bufferSize, out bufferSize))
                    throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());

                TOKEN_USER tokenUser = Marshal.PtrToStructure<TOKEN_USER>(tokenInfoPtr);
                if (!IsValidSid(tokenUser.User.Sid))
                    throw new InvalidOperationException("Invalid user SID.");

                // 3. 获取文件夹的安全描述符(仅DACL)
                if (!GetNamedSecurityInfo(folderPath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, out _, out _, out IntPtr dacl, out _, out IntPtr securityDescriptor))
                    throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());

                try
                {
                    // 4. 定义要检查的所有文件系统权限
                    uint desiredAccess = FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_READ_EA | FILE_WRITE_EA |
                                         FILE_EXECUTE | FILE_DELETE_CHILD | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES |
                                         DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER | SYNCHRONIZE;

                    // 5. 调用AccessCheck计算有效权限
                    uint grantedAccess = 0;
                    uint accessStatus = 0;
                    if (!AccessCheck(securityDescriptor, tokenHandle, desiredAccess, IntPtr.Zero, out _, out grantedAccess, out accessStatus, IntPtr.Zero))
                        throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());

                    // 6. 将原生权限转换为.NET的FileSystemRights枚举
                    return (System.Security.AccessControl.FileSystemRights)grantedAccess;
                }
                finally
                {
                    LocalFree(securityDescriptor);
                }
            }
            finally
            {
                Marshal.FreeHGlobal(tokenInfoPtr);
            }
        }
        finally
        {
            if (tokenHandle != IntPtr.Zero)
                Marshal.Close(tokenHandle);
        }
    }
}

使用示例

你可以这样调用这个方法:

string folderPath = @"C:\YourFolder";
var effectiveRights = EffectivePermissionsHelper.GetEffectiveFolderPermissions(folderPath);
Console.WriteLine($"有效权限:{effectiveRights}");

注意事项

  • 权限要求:你的程序需要有足够的权限读取目标文件夹的安全信息,否则API调用会失败。
  • 权限映射:示例中已经把Windows原生的权限常量和.NET的FileSystemRights做了对应,你可以根据需求调整要检查的权限集合。
  • 指定用户:如果要获取非当前用户的有效权限,你需要先获取该用户的访问令牌(可以用LogonUser API),再传入AccessCheck。

内容的提问来源于stack exchange,提问作者SullenMan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:08:16