Учитывая имя пользователя и пароль, как я исполняю роль того пользователя и выполняю некоторый код как тот пользователь.
И управляемым я имею в виду без pinvokes или dllimports
Это класс-оболочка, который мы создали, который работал на нескольких разных платформах Windows:
public class Impersonator
{
// constants from winbase.h
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_LOGON_NETWORK = 3;
public const int LOGON32_LOGON_BATCH = 4;
public const int LOGON32_LOGON_SERVICE = 5;
public const int LOGON32_LOGON_UNLOCK = 7;
public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
public const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
public const int LOGON32_PROVIDER_DEFAULT = 0;
public const int LOGON32_PROVIDER_WINNT35 = 1;
public const int LOGON32_PROVIDER_WINNT40 = 2;
public const int LOGON32_PROVIDER_WINNT50 = 3;
[DllImport("advapi32.dll", SetLastError=true)]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
public static WindowsImpersonationContext LogOn(string userName, string password)
{
return LogOn(userName, password, "");
}
public static WindowsImpersonationContext LogOn(string userName, string password, string domain)
{
WindowsIdentity tempWindowsIdentity;
WindowsImpersonationContext impersonationContext;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
if(RevertToSelf())
{
if (LogonUserA(userName, domain, password, LOGON32_LOGON_NEW_CREDENTIALS,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
return impersonationContext;
}
}
}
else
{
var win32 = new Win32Exception(Marshal.GetLastWin32Error());
//throw new Exception(string.Format("{0}, Domain:{1}, User:{2}, Password:{3}",
// win32.Message, domain, userName, password));
throw new Exception(win32.Message);
}
}
if(token!= IntPtr.Zero)
CloseHandle(token);
if(tokenDuplicate!=IntPtr.Zero)
CloseHandle(tokenDuplicate);
return null; // Failed to impersonate
}
public static bool LogOff(WindowsImpersonationContext context)
{
bool result = false;
try
{
if (context != null)
{
context.Undo();
result = true;
}
}
catch
{
result = false;
}
return result;
}
}
Я свел это к двум простым методам:
public bool ImpersonateValidUser(String userName, String domain, String password)
public void UndoImpersonation()
Вы можете напрямую скопировать/вставить класс ниже и использовать его в своем проекте:
class ImpersonationContext
{
[DllImport("advapi32.dll")]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
public const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;
public const int LOGON32_PROVIDER_WINNT50 = 3;
WindowsImpersonationContext impersonationContext;
public bool ImpersonateValidUser(String userName, String domain, String password)
{
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
if (RevertToSelf())
{
if (LogonUserA(userName, domain, password, LOGON32_LOGON_NEW_CREDENTIALS,
LOGON32_PROVIDER_WINNT50, ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
return true;
}
}
}
}
if (token != IntPtr.Zero)
CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero)
CloseHandle(tokenDuplicate);
return false;
}
public void UndoImpersonation()
{
impersonationContext.Undo();
}
}
Есть похожий вопрос с отличным ответом здесь.
Посмотрите WindowsImpersonationContext
для получения дополнительной информации (также там есть еще один отличный пример кода)
См. ImpersonationHelper
из Можно ли безопасно получить значение SecureString из VB .NET? . Код готов к работе и надежен.
Он поддерживает IDisposable
, содержит метод RunAs
(который бесценен), пароли обрабатываются как SecureString
и другие полезные мелочи. Я также предоставил тестовый код для класса ImpersonationHelper
, который чрезвычайно полезен для устранения неполадок, и их методы расширения SecureString
пригодятся.