.net 如何在托管代码中模拟用户?

.net 如何在托管代码中模拟用户?,.net,impersonation,.net,Impersonation,给定用户名和密码,我如何模拟该用户并以该用户的身份运行一些代码 我所说的管理是指没有pinvokes或dllimports,有一个类似的问题有一个很好的答案 查看更多信息(还有另一个很棒的代码示例)请参阅的ImpersonationHelper。代码是生产准备好的,健壮的 它支持IDisposable,包含RunAs方法(这是非常宝贵的),密码作为SecureString处理,以及其他一些有用的小东西。我还提供了ImpersonationHelper类的测试代码,该类对故障排除非常有帮助,它们是

给定用户名和密码,我如何模拟该用户并以该用户的身份运行一些代码


我所说的管理是指没有pinvokes或dllimports,有一个类似的问题有一个很好的答案


查看更多信息(还有另一个很棒的代码示例)

请参阅的
ImpersonationHelper
。代码是生产准备好的,健壮的


它支持
IDisposable
,包含
RunAs
方法(这是非常宝贵的),密码作为
SecureString
处理,以及其他一些有用的小东西。我还提供了
ImpersonationHelper
类的测试代码,该类对故障排除非常有帮助,它们是方便使用的
SecureString
扩展方法。

我将其归结为两种简单方法:

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

这是我们创建的包装器类,它已在多个不同的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;
    }
}

我看到的所有示例都没有考虑到登录类型不是一刀切的解决方案这一事实

例如,仅当您模拟的用户具有登录目标系统的权限时,此操作才有效。访问远程SQL Server box时,情况并非总是如此。登录32\u登录\u交互

NetworkClearText是唯一一个可与SQL Server连接一致使用的版本。 -没有明文并不意味着它以不安全的方式传递凭据


当您在工作组中并且需要模拟域用户时,NewCredentials才有效。(未使用SQL Server连接进行测试)

如果是ASP.NET网站,则可以通过在
web.config
中设置
元素来完成。否则,您必须使用导入:(@Simon:Impersonation在安装期间或在“作为”运行应用程序时也很有用)其他人,例如管理员。当然,它可以归结为两种方法。但是,您的代码没有错误处理,如果发生错误,也不会释放它创建的句柄。您在哪里找到LOGON32_PROVIDER_x值?@MicahBurnett我已经有一段时间没有查看此代码了,但评论说我是从winbase.h.an MSDN sea获得的rch或winbase.h搜索应该会提供一些参考。还有