在Windows 7上调用IPrincipal.IsInRole

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

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

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

如果当前用户是Administrator用户,或者是Builtin\Administrators组成员的另一个用户,则Builtin\Administrators

在我们对Windows 7的测试中,我们发现它不再按预期工作。 Administrator用户仍然可以正常工作,但作为Builtin\Administrators组成员的任何其他用户对IsInRole调用返回false。

什么可能导致这种差异? 我有一种直觉,默认设置在某处发生了变化(可能在gpedit中),但找不到任何看起来像罪魁祸首的东西。

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

这是一个讨论该问题的系列文章,其中包含执行必要解决方法的示例代码:

我通过构建自己的UAC提示并使用名称和密码来调用Win32 Logon API,解决了ASP.NET应用程序中的类似问题。 您可能很幸运能够使用.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)); } ///  /// 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. ///  ///  /// 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. ///  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; } 

它改编自我在网上找到的一篇文章,对不起,失去了归属感。

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

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

希望有人发现使用它!

麦克风

我在stackoverflow上找到了另一篇文章,它解决了另一种方式。 我把它改编成下面的方法。 使用Windows 7时,对于管理员,这返回true,对于非管理员,则返回false,对于“以管理员身份运行”,对非管理员返回true。 看起来这只适用于.Net 3.5和XP SP2及更高版本,基于对PolicyContext类的MSDN的初步看法。

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

您的申请没有提升。 在正常情况下,UAC剥离了用户的“管理员”。 如果应用程序只能由管理员使用,请添加一个使其升级的清单,以便他们可以保留其管理员。 如果它可以被任何一个使用,你最好的选择是分成两部分,一部分带有提升清单而另一部分没有,并从一个用盾牌装饰的按钮或菜单项启动提升部分,这样用户就不会点击如果他们不是管理员。 (在较旧的操作系统上,将屏蔽按钮的消息将被忽略。)搜索“UAC”,“分区”和“shellexecute”将会有所帮助。

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

有一些差异:

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