问题描述
我们在应用程序中使用 NTLM 身份验证来确定用户是否可以执行某些操作.我们使用他们当前 Windows 登录的 IPrincipal(在 WinForms 应用程序中),调用 IsInRole 来检查特定的组成员身份.
We use NTLM auth in our application to determine whether a user can perform certain operations. We use the IPrincipal of their current Windows login (in WinForms applications), calling IsInRole to check for specific group memberships.
要检查用户是否是机器上的本地管理员,我们使用:
To check that a user is a local administrator on the machine, we use:
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
...
bool allowed = Thread.CurrentPrincipal.IsInRole(@"BuiltinAdministrators")
如果当前用户是 Administrator
用户,或者是属于 BuiltinAdministrators
组成员的另一个用户,则此方法有效.
This works if the current user is the Administrator
user, or is another user that is a member of the BuiltinAdministrators
group.
在我们对 Windows 7 的测试中,我们发现这不再按预期工作.Administrator
用户仍然可以正常工作,但属于 BuiltinAdministrators
组成员的任何其他用户对 IsInRole
调用返回 false.
In our testing on Windows 7, we have found that this no longer works as expected. The Administrator
user still works fine, but any other user that is a member of the BuiltinAdministrators
group returns false for the IsInRole
call.
什么可能导致这种差异?我有一种直觉,默认设置在某处发生了变化(可能在 gpedit 中),但找不到任何看起来像罪魁祸首的东西.
What could be causing this difference? I have a gut feeling that a default setting has changed somewhere (possible in gpedit), but cannot find anything that looks like the culprit.
推荐答案
问题是 Windows 安全性(又名UAC")正在妨碍您.对管理员角色有特殊处理,您的用户在被提升之前实际上不会拥有这些角色.管理员角色在某种意义上是幻影"的:存在但无法进行权限检查,甚至无法(轻松)测试是否存在.请参阅以下说明:http://msdn.microsoft.com/en-us/library/46ks97y7.aspx
The problem is that Windows security (aka "UAC") is getting in your way. There's special handling of administrator roles and your user will not actually have these roles until he is elevated. Admin roles are "ghosted" in a sense: present but unavailable for permission checks or even to (easily) test for presence. See the note at: http://msdn.microsoft.com/en-us/library/46ks97y7.aspx
这是一个讨论这个问题的系列,并带有执行必要解决方法的示例代码:
Here's a series that talks about the issue, with example code that does the necessary workarounds:
- http://www.simple-talk.com/community/blogs/dana/archive/2008/03/17/45354.aspx
- http://www.simple-talk.com/community/blogs/dana/archive/2008/03/17/45352.aspx
我通过构建自己的 UAC 提示符并使用名称 & 解决了 ASP.NET 应用程序中的类似问题.调用 Win32 登录 API 的密码.您可能很幸运能够使用 .NET 桌面应用程序,在这种情况下,您可以使用常规提升请求.
I solved a similar problem in an ASP.NET app by building my own UAC prompt and using the name & password to call the Win32 Logon API. You might be lucky enough to be in a .NET desktop app, in which case you can use regular elevation requests.
这里有一些 C# 代码可以在不提升权限的情况下检查管理员权限.
Here's some C# code to check admin permissions without elevating.
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;
}
改编自网上某处的一篇文章,抱歉,署名丢失了.
It's adapted from an article I found online somewhere, sorry, lost the attribution.
这篇关于在 Windows 7 上调用 IPrincipal.IsInRole的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!