.net - .NET 模拟登录线程安全吗?

标签 .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))

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

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

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

让我担心的是MSDN页面WindowsImpersonationContext 上的声明上面写着:

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

模仿者类:

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 )或进程(通过 CreateProcess API function 或通过模拟线程,然后创建一个新的 Process 实例,同时冒充用户)。

无论哪种方式,请调用 LogonUser API function不执行任何模拟,它只是为您提供执行模拟所需的用户句柄(假设您有权限)。

关于.net - .NET 模拟登录线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3833656/

相关文章:

c# - 在另一台机器上模拟本地用户

.net - 使用 DataContractSerializer 和 MetaDataTypeAttribute 问题自动生成 POCO 序列化

.net - CLR(公共(public)语言运行时)的哪一部分负责创建对象?

c# - 构建Android项目时出现奇怪的错误(Xamarin)

ASP.NET - 在默认情况下临时模拟应用程序池服务 ID 来模拟用户?

c# - 无法在 DLL 'LogonUser' 模拟异常中找到名为 'advapi32.dll' 的入口点

c++ - ImpersonateLoggedOnUser 似乎不起作用

c# - 按数组元素排序 Linq 列表

c# - 跨多个折线图的垂直线,并在 Winforms 中显示每个图表的值

windows - 是否可以在 VB.NET 中复制以下凭证过程?