如何在C#程序中模拟域帐户进行登录操作 (转载)

.NET Core


.NET Core也支持用PInvoke来调用操作系统底层的Win32函数

首先要在项目中下载Nuget包:System.Security.Principal.Windows

 

代码加注释:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Principal;


namespace NetCorePrincipal
{
    public class WindowsLogin : IDisposable
    {
        protected const int LOGON32_PROVIDER_DEFAULT = 0;
        protected const int LOGON32_LOGON_INTERACTIVE = 2;

        public WindowsIdentity Identity = null;
        protected IntPtr m_accessToken;


        [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 extern static bool CloseHandle(IntPtr handle);


        // AccessToken ==> this.Identity.AccessToken
        //public Microsoft.Win32.SafeHandles.SafeAccessTokenHandle AT
        //{
        //    get
        //    {
        //        var at = new Microsoft.Win32.SafeHandles.SafeAccessTokenHandle(this.m_accessToken);
        //        return at;
        //    }
        //}

        public WindowsLogin(string username, string domain, string password)
        {
            Login(username, domain, password);
        }


        public void Login(string username, string domain, string password)
        {
            if (this.Identity != null)
            {
                this.Identity.Dispose();
                this.Identity = null;
            }


            try
            {
                this.m_accessToken = new IntPtr(0);
                Logout();

                this.m_accessToken = IntPtr.Zero;
                bool logonSuccessfull = LogonUser(
                   username,
                   domain,
                   password,
                   LOGON32_LOGON_INTERACTIVE,
                   LOGON32_PROVIDER_DEFAULT,
                   ref this.m_accessToken);

                if (!logonSuccessfull)
                {
                    int error = Marshal.GetLastWin32Error();
                    throw new System.ComponentModel.Win32Exception(error);
                }
                Identity = new WindowsIdentity(this.m_accessToken);
            }
            catch
            {
                throw;
            }

        }


        public void Logout()
        {
            if (this.m_accessToken != IntPtr.Zero)
                CloseHandle(m_accessToken);

            this.m_accessToken = IntPtr.Zero;

            if (this.Identity != null)
            {
                this.Identity.Dispose();
                this.Identity = null;
            }

        } // End Sub Logout 


        public void Dispose()
        {
            Logout();
        } // End Sub Dispose 

    } // End Class WindowsLogin 



    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"Current user is : {WindowsIdentity.GetCurrent().Name}");

            using (WindowsLogin wi = new WindowsLogin("uid", "serverdomain", "pwd"))
            {
                WindowsIdentity.RunImpersonated(wi.Identity.AccessToken, () =>
                {
                    Console.WriteLine($"Current user is : {WindowsIdentity.GetCurrent().Name}");

                    //假定要操作的文件路径是10.0.250.11上的d:\txt.txt文件可以这样操作
                    FileInfo file = new FileInfo(@"\\10.0.250.11\d$\txt.txt");
                    //想做什么操作就可以做了
                });
            }

            Console.WriteLine($"Current user is : {WindowsIdentity.GetCurrent().Name}");

            Console.WriteLine("Press any key to quit...");
            Console.ReadKey();
        }
    }
}

 

 

.NET Framework


代码加注释:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Principal;


namespace NetFrameworkPrincipal
{
    public class WindowsLogin : IDisposable
    {
        protected const int LOGON32_PROVIDER_DEFAULT = 0;
        protected const int LOGON32_LOGON_INTERACTIVE = 2;

        public WindowsIdentity Identity = null;
        protected IntPtr m_accessToken;


        [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 extern static bool CloseHandle(IntPtr handle);


        // AccessToken ==> this.Identity.AccessToken
        //public Microsoft.Win32.SafeHandles.SafeAccessTokenHandle AT
        //{
        //    get
        //    {
        //        var at = new Microsoft.Win32.SafeHandles.SafeAccessTokenHandle(this.m_accessToken);
        //        return at;
        //    }
        //}

        public WindowsLogin(string username, string domain, string password)
        {
            Login(username, domain, password);
        }


        public void Login(string username, string domain, string password)
        {
            if (this.Identity != null)
            {
                this.Identity.Dispose();
                this.Identity = null;
            }


            try
            {
                this.m_accessToken = new IntPtr(0);
                Logout();

                this.m_accessToken = IntPtr.Zero;
                bool logonSuccessfull = LogonUser(
                   username,
                   domain,
                   password,
                   LOGON32_LOGON_INTERACTIVE,
                   LOGON32_PROVIDER_DEFAULT,
                   ref this.m_accessToken);

                if (!logonSuccessfull)
                {
                    int error = Marshal.GetLastWin32Error();
                    throw new System.ComponentModel.Win32Exception(error);
                }
                Identity = new WindowsIdentity(this.m_accessToken);
            }
            catch
            {
                throw;
            }

        }


        public void Logout()
        {
            if (this.m_accessToken != IntPtr.Zero)
                CloseHandle(m_accessToken);

            this.m_accessToken = IntPtr.Zero;

            if (this.Identity != null)
            {
                this.Identity.Dispose();
                this.Identity = null;
            }

        } // End Sub Logout 


        public void Dispose()
        {
            Logout();
        } // End Sub Dispose 

    } // End Class WindowsLogin 



    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"Current user is : {WindowsIdentity.GetCurrent().Name}");

            using (WindowsLogin wi = new WindowsLogin("uid", "serverdomain", "pwd"))
            {
                //WindowsIdentity.RunImpersonated(wi.Identity.AccessToken, () =>
                //{
                //    //假定要操作的文件路径是10.0.250.11上的d:\txt.txt文件可以这样操作
                //    FileInfo file = new FileInfo(@"\\10.0.250.11\d$\txt.txt");
                //    //想做什么操作就可以做了
                //});

                using (wi.Identity.Impersonate())
                {
                    Console.WriteLine($"Current user is : {WindowsIdentity.GetCurrent().Name}");

                    //假定要操作的文件路径是10.0.250.11上的d:\txt.txt文件可以这样操作
                    FileInfo file = new FileInfo(@"\\10.0.250.11\d$\txt.txt");
                    //想做什么操作就可以做了
                }
            }

            Console.WriteLine($"Current user is : {WindowsIdentity.GetCurrent().Name}");

            Console.WriteLine("Press any key to quit...");
            Console.ReadKey();
        }
    }
}

 

模拟域帐户之后,就有了模拟用户的权限,这里千万要注意安全!

 

 

模拟的域帐户是和线程绑定的


需要注意的一点是,模拟的域账户是和C#中的线程绑定的。

 

例如下面.NET Core控制台项目中,我们在Program类的Main方法中,模拟域账户UserB后,再启动一个新的线程去查看当前用户,还是显示的是UserB,代码如下所示:

using System;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;

namespace NetCorePrincipal
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"Current user is : {WindowsIdentity.GetCurrent().Name}");//输出当前用户为UserA

            //模拟域帐户UserB
            using (WindowsLogin wi = new WindowsLogin("UserB", "Domain", "1qaz!QAZ"))
            {
                WindowsIdentity.RunImpersonated(wi.Identity.AccessToken, () =>
                {
                    Console.WriteLine("Impersonation started.");
                    Console.WriteLine($"Current user is : {WindowsIdentity.GetCurrent().Name}");//输出当前用户为UserB

                    //启动另一个线程查看当前用户
                    Task.Run(() =>
                    {
                        Console.WriteLine($"Current user in another thread is : {WindowsIdentity.GetCurrent().Name}");//输出当前用户为UserB
                    }).Wait();//等待启动的线程执行完毕

                    Console.WriteLine("Impersonation finished.");
                });
            }

            Console.WriteLine($"Current user is : {WindowsIdentity.GetCurrent().Name}");//输出当前用户为UserA

            Console.WriteLine("Press any key to quit...");
            Console.ReadKey();
        }
    }
}

输出结果如下所示:

Current user is : Domain\UserA
Impersonation started.
Current user is : Domain\UserB
Current user in another thread is : Domain\UserB
Impersonation finished.
Current user is : Domain\UserA
Press any key to quit...

 

但是接下来我们更改Program类的Main方法代码,在模拟域账户UserB前先启动一个新的线程,然后模拟域账户UserB后,在新启动的线程中查看当前用户,会显示当前用户是UserA,代码如下所示:

using System;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;

namespace NetCorePrincipal
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"Current user is : {WindowsIdentity.GetCurrent().Name}");//输出当前用户为UserA

            //启动另一个线程查看当前用户
            var newTask = Task.Run(() =>
            {
                Thread.Sleep(3000);
                Console.WriteLine($"Current user in another thread is : {WindowsIdentity.GetCurrent().Name}");//输出当前用户为UserA
            });

            //模拟域帐户UserB
            using (WindowsLogin wi = new WindowsLogin("UserB", "Domain", "1qaz!QAZ"))
            {
                WindowsIdentity.RunImpersonated(wi.Identity.AccessToken, () =>
                {
                    Console.WriteLine("Impersonation started.");
                    Console.WriteLine($"Current user is : {WindowsIdentity.GetCurrent().Name}");//输出当前用户为UserB

                    newTask.Wait();//等待启动的线程执行完毕

                    Console.WriteLine("Impersonation finished.");
                });
            }

            Console.WriteLine($"Current user is : {WindowsIdentity.GetCurrent().Name}");//输出当前用户为UserA

            Console.WriteLine("Press any key to quit...");
            Console.ReadKey();
        }
    }
}

输出结果如下所示:

Current user is : Domain\UserA
Impersonation started.
Current user is : Domain\UserB
Current user in another thread is : Domain\UserA
Impersonation finished.
Current user is : Domain\UserA
Press any key to quit...

 

由此可见模拟的域帐户实际上是和线程绑定的,新启动的线程会继承启动它的线程的域帐户。

  • 如果线程A的当前域帐户是UserA,然后线程A启动了线程B,那么启动的线程B当前域帐户也会是UserA。
  • 如果线程A的当前域帐户是UserA,然后线程A使用本文所述方法模拟域帐户UserB,再启动线程B,那么启动的线程B当前域帐户会是UserB。

 

转载于:https://www.cnblogs.com/OpenCoder/p/10029870.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值