代码之家  ›  专栏  ›  技术社区  ›  adrianbanks

在Windows 7上调用iprincipal.isinRole

  •  8
  • adrianbanks  · 技术社区  · 16 年前

    我们在应用程序中使用ntlm auth来确定用户是否可以执行某些操作。我们使用 IPrincipal 当前的Windows登录(在WinForms应用程序中),调用 IsInRole 检查特定的组成员身份。

    要检查用户是否是计算机上的本地管理员,我们使用:

    AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
    ...
    bool allowed = Thread.CurrentPrincipal.IsInRole(@"Builtin\Administrators")
    

    如果当前用户是 Administrator 用户,或者是 Builtin\Administrators 组。

    在我们对Windows7的测试中,我们发现这不再像预期的那样有效。这个 管理员 用户仍然可以正常工作,但属于 内置\管理员 组返回false IsInRole 打电话。

    造成这种差异的原因是什么?我有种直觉,认为默认设置在某个地方发生了变化(在gpedit中是可能的),但找不到任何看起来像罪魁祸首的东西。

    5 回复  |  直到 12 年前
        1
  •  9
  •   Steve Eisner    16 年前

    问题是Windows安全(又称“UAC”)正在妨碍您的工作。管理员角色有特殊的处理方式,在提升之前,您的用户实际上不会拥有这些角色。管理角色在某种意义上是“幻影”:存在但不可用于权限检查,甚至无法(轻松)测试是否存在。见注释: http://msdn.microsoft.com/en-us/library/46ks97y7.aspx

    下面是一个讨论这个问题的系列,示例代码提供了必要的解决方法:

    我在ASP.NET应用程序中解决了类似的问题,方法是构建自己的UAC提示,并使用名称和密码调用win32登录API。你可能很幸运能加入.NET桌面应用程序,在这种情况下,你可以使用常规的提升请求。

    下面是一些C代码,用于检查管理权限而不提升。

        public const UInt32 TOKEN_DUPLICATE = 0x0002;
        public const UInt32 TOKEN_IMPERSONATE = 0x0004;
        public const UInt32 TOKEN_QUERY = 0x0008;
    
        public enum TOKEN_ELEVATION_TYPE
        {
            TokenElevationTypeDefault = 1,
            TokenElevationTypeFull,
            TokenElevationTypeLimited
        }
    
        public enum TOKEN_INFORMATION_CLASS
        {
            TokenUser = 1,
            TokenGroups,
            TokenPrivileges,
            TokenOwner,
            TokenPrimaryGroup,
            TokenDefaultDacl,
            TokenSource,
            TokenType,
            TokenImpersonationLevel,
            TokenStatistics,
            TokenRestrictedSids,
            TokenSessionId,
            TokenGroupsAndPrivileges,
            TokenSessionReference,
            TokenSandBoxInert,
            TokenAuditPolicy,
            TokenOrigin,
            TokenElevationType,
            TokenLinkedToken,
            TokenElevation,
            TokenHasRestrictions,
            TokenAccessInformation,
            TokenVirtualizationAllowed,
            TokenVirtualizationEnabled,
            TokenIntegrityLevel,
            TokenUIAccess,
            TokenMandatoryPolicy,
            TokenLogonSid,
            MaxTokenInfoClass  // MaxTokenInfoClass should always be the last enum 
        }
    
        public enum SECURITY_IMPERSONATION_LEVEL
        {
            SecurityAnonymous,
            SecurityIdentification,
            SecurityImpersonation,
            SecurityDelegation
        }
    
    
        public static bool IsAdmin()
        {
            var identity = WindowsIdentity.GetCurrent();
            return (null != identity && new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator));
        }
    
        /// <summary>
        /// The function checks whether the primary access token of the process belongs
        /// to user account that is a member of the local Administrators group, even if
        /// it currently is not elevated.
        /// </summary>
        /// <returns>
        /// Returns true if the primary access token of the process belongs to user
        /// account that is a member of the local Administrators group. Returns false
        /// if the token does not.
        /// </returns>
        public static bool CanBeAdmin()
        {
            bool fInAdminGroup = false;
            IntPtr hToken = IntPtr.Zero;
            IntPtr hTokenToCheck = IntPtr.Zero;
            IntPtr pElevationType = IntPtr.Zero;
            IntPtr pLinkedToken = IntPtr.Zero;
            int cbSize = 0;
    
            if (IsAdmin())
                return true;
    
            try
            {
                // Check the token for this user
                hToken = WindowsIdentity.GetCurrent().Token;
    
                // Determine whether system is running Windows Vista or later operating
                // systems (major version >= 6) because they support linked tokens, but
                // previous versions (major version < 6) do not.
                if (Environment.OSVersion.Version.Major >= 6)
                {
                    // Running Windows Vista or later (major version >= 6).
                    // Determine token type: limited, elevated, or default.
    
                    // Allocate a buffer for the elevation type information.
                    cbSize = sizeof(TOKEN_ELEVATION_TYPE);
                    pElevationType = Marshal.AllocHGlobal(cbSize);
                    if (pElevationType == IntPtr.Zero)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
    
                    // Retrieve token elevation type information.
                    if (!GetTokenInformation(hToken,
                        TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType, cbSize, out cbSize))
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
    
                    // Marshal the TOKEN_ELEVATION_TYPE enum from native to .NET.
                    TOKEN_ELEVATION_TYPE elevType = (TOKEN_ELEVATION_TYPE)Marshal.ReadInt32(pElevationType);
    
                    // If limited, get the linked elevated token for further check.
                    if (elevType == TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited)
                    {
                        // Allocate a buffer for the linked token.
                        cbSize = IntPtr.Size;
                        pLinkedToken = Marshal.AllocHGlobal(cbSize);
                        if (pLinkedToken == IntPtr.Zero)
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                        }
    
                        // Get the linked token.
                        if (!GetTokenInformation(hToken,
                            TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken,
                            cbSize, out cbSize))
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                        }
    
                        // Marshal the linked token value from native to .NET.
                        hTokenToCheck = Marshal.ReadIntPtr(pLinkedToken);
                    }
                }
    
                // CheckTokenMembership requires an impersonation token. If we just got
                // a linked token, it already is an impersonation token.  If we did not
                // get a linked token, duplicate the original into an impersonation
                // token for CheckTokenMembership.
                if (hTokenToCheck == IntPtr.Zero)
                {
                    if (!DuplicateToken(hToken, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, ref hTokenToCheck))
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                }
    
                // Check if the token to be checked contains admin SID.
                WindowsIdentity id = new WindowsIdentity(hTokenToCheck);
                WindowsPrincipal principal = new WindowsPrincipal(id);
                fInAdminGroup = principal.IsInRole(WindowsBuiltInRole.Administrator);
            }
            catch
            {
                return false;
            }
            finally
            {
                // Centralized cleanup for all allocated resources.
                if (pElevationType != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pElevationType);
                    pElevationType = IntPtr.Zero;
                }
                if (pLinkedToken != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pLinkedToken);
                    pLinkedToken = IntPtr.Zero;
                }
            }
    
            return fInAdminGroup;
        }
    

    它改编自我在网上某个地方发现的一篇文章,对不起,失去了归属感。

        2
  •  7
  •   Michael Watts    15 年前

    这对我有效-我所需要的只是检查程序是否以管理员角色启动:

       public static bool IsAdminRole()
        {
            AppDomain domain = Thread.GetDomain();
    
            domain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
            WindowsPrincipal principle = (WindowsPrincipal)Thread.CurrentPrincipal;
            return principle.IsInRole(WindowsBuiltInRole.Administrator);
        }
    

    希望有人找到有用的!

    迈克

        3
  •  3
  •   DavB.cs    14 年前

    我在StackOverflow上找到了另一篇文章,它用另一种方式来解决这个问题。 我把它改编成下面的方法。 使用Windows7时,对于管理员返回true,对于非管理员返回false,对于非管理员在“以管理员身份运行”时返回true。 根据对PrincipleContext类的msdn的初步了解,这似乎只适用于.NET 3.5和xp sp2及更高版本。

    private static bool IsUserAdmin()
    {
        bool isAdmin = false;
    
        WindowsIdentity wi = WindowsIdentity.GetCurrent();
        WindowsPrincipal wp = new WindowsPrincipal(wi);
        isAdmin = wp.IsInRole(WindowsBuiltInRole.Administrator);
    
        Console.WriteLine(isAdmin); // False for Windows 7 even if user is admin
    
        //found the code below at [http://stackoverflow.com/questions/1089046/in-net-c-test-if-user-is-an-administrative-user][1]  
    
        // Add reference to System.DirectoryServices.AccountManagement (Add Referemce -> .Net)
        // Add using System.DirectoryServices.AccountManagement;
    
        if (!isAdmin) //PrincipleContext takes a couple seconds, so I don't use it if not necessary
        {
            using (PrincipalContext pc = new PrincipalContext(ContextType.Machine, null))
            {
                UserPrincipal up = UserPrincipal.Current;
                GroupPrincipal gp = GroupPrincipal.FindByIdentity(pc, "Administrators");
                if (up.IsMemberOf(gp))
                {
                    isAdmin = true;
                }
            }
        }
        Console.WriteLine(isAdmin); // True for Windows 7 if user is admin
    
    
        return isAdmin;
    }
    
        4
  •  1
  •   Kate Gregory    16 年前

    您的应用程序未提升。在正常情况下,UAC会剥夺用户的“管理员资格”。如果应用程序只能由管理员使用,请添加一个清单,使其提升,以便他们可以保持自己的管理性。如果两者都可以使用,那么最好的办法是将其分为两部分,一部分带有升降舱单,另一部分不带升降舱单,然后从装饰有护罩的按钮或菜单项启动升降舱单,这样用户如果不是管理员,就不会单击它。(在旧操作系统上,将屏蔽放在按钮上的消息将被忽略。)搜索“uac”、“partition”和“shellexecute”将有所帮助。

        5
  •  0
  •   Tiele Declercq    12 年前

    我使用了与davb.cs相同的方法: http://tieledeclercq.blogspot.be/2013/09/c-is-this-valid-administrator-that-can.html

    有一些区别:

    1. 管理员可以是本地管理员组的嵌套成员。
    2. 我需要使用外部凭据(而不是当前用户)。