Dot-Net

.NET 模擬登錄執行緒安全嗎?

  • December 13, 2017

如果使用如下程式碼模擬其他使用者,

[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))

在兩個不同的並發執行緒上,它們會相互干擾嗎?即,目前登錄的使用者是與執行緒相關聯的,還是與主機程序相關聯的?

我正在使用登錄句柄創建一個 WindowsImpersonationContext 對象,作為我命名為“Impersonator”的類型實例中的私有狀態欄位(程式碼如下)。因此,由於此 WindowsImpersonationContext 對像是此類型實例中的本地私有欄位,並且每次我想模擬某些憑據集時都會創建此類型的新實例,因此我可以假設此 WindowsImpersonationContext 是用於在塊內執行程式碼期間執行所有 ACL 驗證,例如

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

我擔心的是 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
}

它與任何事物無關。您擁有的句柄是登錄句柄。一旦你有了它,你就可以使用該句柄線上程上(通過呼叫WindowsIdentity.Impersonate)或程序(通過CreateProcessAPI 函式或通過線上程上模擬,然後在模擬使用者時創建新Process實例)來模擬使用者。

無論哪種方式,呼叫LogonUserAPI 函式都不會執行任何模擬,它只是為您提供執行模擬所需的使用者句柄(假設您有權限)。

引用自:https://stackoverflow.com/questions/3833656