.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 = ;
protected const int LOGON32_LOGON_INTERACTIVE = ; 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();
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 = ;
protected const int LOGON32_LOGON_INTERACTIVE = ; 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();
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();
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。

如何在C#程序中模拟域帐户进行登录操作 (转载)的更多相关文章

  1. 【转】如何在 Android 程序中禁止屏幕旋转和重启Activity

    原文网址:http://www.cnblogs.com/bluestorm/p/3665890.html 禁止屏幕随手机旋转变化 有时候我们希望让一个程序的界面始终保持在一个方向,不随手机方向旋转而变 ...

  2. 如何在 Android 程序中禁止屏幕旋转和重启Activity

    禁止屏幕随手机旋转变化 有时候我们希望让一个程序的界面始终保持在一个方向,不随手机方向旋转而变化:在AndroidManifest.xml的每一个需要禁止转向的Activity配置中加入android ...

  3. Windows域帐户

    域的直观优点: 1.域帐户可以在任意一台已经加入域的电脑上登录. 2.将域用户组加入到SQL Server登录里,域用户组内所有人员便都可以使用域用户登录数据库,继承相关权限. 3.域用户登录Team ...

  4. sharepoint 2013创建网站集,域帐户无法访问,只有administrator可以访问

    解决方法: 1.创建WEB应用程序时,可配置帐户必须为域帐户 2.确定关闭防火墙(这是重点) 我在测试时发现80端口和30714端口在其它同事的电脑上(域帐户)都可以访问,除这两个端口以后都无法访问, ...

  5. [转]删除SQL Server Management Studio中保存的帐户信息

    http://www.2cto.com/database/201208/149850.html   删除SQL Server Management Studio中保存的帐户信息   SQL Serve ...

  6. SQL Server 2008读取域帐户信息

    参考:http://www.pawlowski.cz/2011/04/querying-active-directory-sql-server-t-sql/ 1.建立  link server . u ...

  7. 在java程序中,对于数据的输入/输出操作以“流”(stream)方式进行

    在java程序中,对于数据的输入/输出操作以“流”(stream)方式进行

  8. 如何在RCP程序中添加一个banner栏

    前言:这段时间还算比较空闲,我准备把过去做过的有些形形色色,甚至有些奇怪的研究总结一下,也许刚好有人用的着也不一定,不枉为之抓耳挠腮的时光和浪费的电力.以前有个客户提出要在RCP程序中添加一个bann ...

  9. 如何在java程序中调用linux命令或者shell脚本

    转自:http://blog.sina.com.cn/s/blog_6433391301019bpn.html 在java程序中如何调用linux的命令?如何调用shell脚本呢? 这里不得不提到ja ...

随机推荐

  1. Docker for Windows(三)Docker镜像与容器的区别&常用命令

    Docker镜像(Image)是一堆只读文件(read-only layer),容器(container)的定义和镜像(image)几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是 ...

  2. Storm默认配置 default.yaml

    default.yaml文件所在位置:apache-storm-0.9.4.tar.gz/apache-storm-0.9.4/lib/storm-core-0.94.jar/default.yaml ...

  3. webapp开发绝对定位引发的问题

    最近做了一个webapp 需求是要滑动页面翻页,我使用了大量绝对定位 当遇到输入框时,在部分手机上发现了问题.虚拟键盘收回时,整个body全部下移了,经过多次测试, 发现是fixed布局的音乐按钮造成 ...

  4. Debian出现in the drive ‘/media/cdrom/’ and press enter解决办法

    没有光盘源解决打开/etc/apt/sources.list文件,注释掉cdrom那一行,然后再执行apt-get update更新下deb仓库这样以后再使用apt-get安装时就不会再搜寻cdrom ...

  5. springboot学习入门之四---开发Web应用之Thymeleaf篇

    http://tengj.top/2017/03/13/springboot4/ 1项目结构 说明: root package结构:com.dudu 应用启动类Application.java置于ro ...

  6. UpdateServer事务实现机制

    UpdateServer(UPS) 是OceanBase的写入单点,一个集群中只有一台UPS服务器,所有的写都写入到这台机器.OceanBase采用基于静动态数据分离的机制,静态数据存储在静态数据服务 ...

  7. Redis搜索引擎设计

    以下图片是基于自身对知识掌握的基本能力而画出的,并没有系统全面的读过活跃于互联网大牛的著作(个人认为那样会限制自身的思维空间),因此,若图片里存在错误,敬请批评指正,谢谢! 除非互联网项目,传统的制造 ...

  8. 1.windows下Redis安装

    参考文档:https://www.cnblogs.com/Leo_wl/p/6392196.html?utm_source=itdadao&utm_medium=referral Redis数 ...

  9. 工具类-vim在shell中卡死的情况

    time:2015/11/35 在xshell下面使用vim编辑,有时候会出现突然卡死的情况.但是如果重新开一个终端的话,打开文件又是一大堆问题,今天又碰到了,搜了一下就找到一个帮助了[1] 原因:按 ...

  10. Linux 文件特殊权限详解[suid/sgid/t]

    setuid(suid): 针对命令和二进制程序的,当普通用户执行某个(passwd)命令的时候,可以拥有这个命令对应用户的权限, 即让普通用户可以以root用户的角色执行程序或命令. setgid( ...