.NET模拟登录是否是线程安全的?

Cha*_*ana 13 .net impersonation

如果使用以下代码来模仿其他用户,

[DllImport("advapi32.dll", SetLastError = true)]

private static extern bool

LogonUser(string lpszUsername, string lpszDomain,
          string lpszPassword, int dwLogonType,
          int dwLogonProvider, ref IntPtr phToken);
var handle = IntPtr.Zero;

const int LOGON32_LOGON_NETWORK = 3;
const int LOGON32_PROVIDER_DEFAULT = 0;
const int SecurityImpersonation = 2;
LogonUser(username, domain,
          password, LOGON32_LOGON_NETWORK,
          LOGON32_PROVIDER_DEFAULT, ref handle))
Run Code Online (Sandbox Code Playgroud)

在两个不同的并发线程上,它们会相互干扰吗?即,当前登录的用户是与线程关联还是与主机进程关联?

我使用登录句柄创建一个WindowsImpersonationContext对象,作为名为"Impersonator"的类型的实例中的私有状态字段(下面的代码).因此,由于此WindowsImpersonationContext对象是此类型实例中的本地专用字段,并且每次我想模拟某些凭据集时都会创建此类型的新实例,我可以假设此WindowsImpersonationContext正在用于在块内执行代码期间执行所有ACL验证,例如

   using (Impersonator.Impersonate(userId, domain, password))
   {
       // Code I want to execute using supplied credentials
   }
Run Code Online (Sandbox Code Playgroud)

我关心的是MSDN页面上的声明WindowsImpersonationContext说:

此类型的任何公共静态(在Visual Basic中为Shared)成员都是线程安全的.任何实例成员都不保证是线程安全的.

Impersonator 类:

public class Impersonator: IDisposable
{
    #region Declarations
        private readonly string username;
        private readonly string password;
        private readonly string domain;

        // This will hold the security context
        // for reverting back to the client after
        // impersonation operations are complete
        private WindowsImpersonationContext impersonationContext;
    #endregion Declarations

    #region Constructors

        public Impersonator(string UserName,
            string Domain, string Password)
        {
            username = UserName;
            domain = Domain;
            password = Password;
        }
    #endregion Constructors

    #region Public Methods
        public static Impersonator Impersonate(
            string userName, string domain, string password)
        {
            var imp = new Impersonator(userName, domain, password);
            imp.Impersonate();
            return imp;
        }

        public void Impersonate()
        {
            impersonationContext = Logon().Impersonate();
        }

        public void Undo() {
            impersonationContext.Undo();
        }
    #endregion Public Methods

    #region Private Methods
        private WindowsIdentity Logon()
        {
            var handle = IntPtr.Zero;

            const int LOGON32_LOGON_NETWORK = 3;
            const int LOGON32_PROVIDER_DEFAULT = 0;
            const int SecurityImpersonation = 2;

            // Attempt to authenticate domain user account
            try
            {
                if (!LogonUser(username, domain,
                    password, LOGON32_LOGON_NETWORK,
                    LOGON32_PROVIDER_DEFAULT, ref handle))
                    throw new LogonException(
                        "User logon failed. Error Number: " +
                        Marshal.GetLastWin32Error());

                // ----------------------------------
                var dupHandle = IntPtr.Zero;
                if (!DuplicateToken(handle,
                    SecurityImpersonation,
                    ref dupHandle))
                    throw new LogonException(
                        "Logon failed attemting to duplicate handle");

                // Logon Succeeded ! return new WindowsIdentity instance
                return (new WindowsIdentity(handle));
            }
            // Close the open handle to the authenticated account
            finally { CloseHandle(handle); }
        }

        #region external Win32 API functions
            [DllImport("advapi32.dll", SetLastError = true)]
            private static extern bool
                LogonUser(string lpszUsername, string lpszDomain,
                        string lpszPassword, int dwLogonType,
                        int dwLogonProvider, ref IntPtr phToken);

            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            private static extern bool CloseHandle(IntPtr handle);
            // --------------------------------------------

            [DllImport("advapi32.dll", CharSet = CharSet.Auto,
                 SetLastError = true)]
            public static extern bool DuplicateToken(
                IntPtr ExistingTokenHandle,
                int SECURITY_IMPERSONATION_LEVEL,
                ref IntPtr DuplicateTokenHandle);
            // --------------------------------------------
        #endregion external Win32 API functions
    #endregion Private Methods

    #region IDisposable
        private bool disposed;

        public void Dispose() { Dispose(true); }

        public void Dispose(bool isDisposing)
        {
            if (disposed)
                return;
            if (isDisposing)
                Undo();
            // -----------------
            disposed = true;
            GC.SuppressFinalize(this);
        }

        ~Impersonator() {
            Dispose(false);
        }

    #endregion IDisposable
}
Run Code Online (Sandbox Code Playgroud)

cas*_*One 5

它与任何东西都无关.您拥有的句柄是登录句柄.完成后,使用该句柄在线程上模拟用户(通过调用WindowsIdentity.Impersonate)或进程(通过CreateProcessAPI函数或模拟线程,然后Process在模拟用户时创建新实例).

无论哪种方式,调用LogonUserAPI函数都不会执行任何模拟,它只是为您提供了一个您需要执行模拟的用户句柄(假设您拥有该权限).