.NET 空间中的“模拟”通常意味着在特定用户帐户下运行代码。与通过用户名和密码访问该用户帐户相比,这是一个有点不同的概念,尽管这两个想法经常结合在一起。我将描述它们,然后解释如何使用我的 SimpleImpersonation 库,它在内部使用它们。
假冒
用于模拟的 API 在 .NET 中通过 System.Security.Principal 命名空间提供:
-
较新的代码(.NET 4.6+、.NET Core 等)通常应使用WindowsIdentity.RunImpersonated,它接受用户帐户令牌的句柄,然后是Action 或Func<T>要执行的代码。
WindowsIdentity.RunImpersonated(tokenHandle, () =>
{
// do whatever you want as this user.
});
或
var result = WindowsIdentity.RunImpersonated(tokenHandle, () =>
{
// do whatever you want as this user.
return result;
});
-
旧代码使用WindowsIdentity.Impersonate 方法检索WindowsImpersonationContext 对象。该对象实现了IDisposable,因此一般应从using 块中调用。
using (WindowsImpersonationContext context = WindowsIdentity.Impersonate(tokenHandle))
{
// do whatever you want as this user.
}
虽然此 API 在 .NET Framework 中仍然存在,但通常应避免使用,并且在 .NET Core 或 .NET Standard 中不可用。
访问用户帐户
在 Windows 中使用用户名和密码访问用户帐户的 API 是 LogonUser - 这是一个 Win32 本机 API。目前没有用于调用它的内置 .NET API,因此必须求助于 P/Invoke。
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);
这是基本的调用定义,但是要在生产中实际使用它还有很多需要考虑:
- 获取具有“安全”访问模式的句柄。
- 适当关闭本机句柄
- 代码访问安全 (CAS) 信任级别(仅在 .NET Framework 中)
- 当您可以通过用户击键安全地收集一个时,传递
SecureString。
为说明所有这些而编写的代码量超出了 StackOverflow 答案中的内容,恕我直言。
一种更简单的组合方法
与其自己编写所有这些,不如考虑使用我的 SimpleImpersonation 库,它将模拟和用户访问结合到一个 API 中。它在现代和旧代码库中都能很好地工作,使用相同的简单 API:
var credentials = new UserCredentials(domain, username, password);
Impersonation.RunAsUser(credentials, logonType, () =>
{
// do whatever you want as this user.
});
或
var credentials = new UserCredentials(domain, username, password);
var result = Impersonation.RunAsUser(credentials, logonType, () =>
{
// do whatever you want as this user.
return something;
});
请注意,它与WindowsIdentity.RunImpersonated API 非常相似,但不需要您了解任何有关令牌句柄的知识。
这是 3.0.0 版的 API。有关更多详细信息,请参阅项目自述文件。另请注意,该库的早期版本使用IDisposable 模式的API,类似于WindowsIdentity.Impersonate。较新的版本更安全,而且两者仍在内部使用。