是否有一种简单的开箱即用方式来模拟.NET中的用户?
到目前为止,我一直在代码项目中使用这个类来满足我的所有模拟要求.
有没有更好的方法来使用.NET Framework?
我有一个用户凭据集(用户名,密码,域名),表示我需要模拟的身份.
.NET空间中的"模拟"通常意味着在特定用户帐户下运行代码.这是一个有点单独的概念,而不是通过用户名和密码访问该用户帐户,尽管这两个想法经常配对.我将描述它们,然后解释如何使用我的SimpleImpersonation库,它在内部使用它们.
用于模拟的API通过System.Security.Principal
命名空间在.NET中提供:
通常应使用较新的代码(.NET 4.6 +,.NET Core等)WindowsIdentity.RunImpersonated
,它接受用户帐户令牌的句柄,然后接受Action
或Func
执行代码.
WindowsIdentity.RunImpersonated(tokenHandle, () => { // do whatever you want as this user. });
要么
var result = WindowsIdentity.RunImpersonated(tokenHandle, () => { // do whatever you want as this user. return result; });
较旧的代码使用该WindowsIdentity.Impersonate
方法来检索WindowsImpersonationContext
对象.该对象实现IDisposable
,因此通常应该从using
块调用.
using (WindowsImpersonationContext context = WindowsIdentity.Impersonate(tokenHandle)) { // do whatever you want as this user. }
虽然此API仍然存在于.NET Framework中,但通常应该避免使用,并且在.NET Core或.NET Standard中不可用.
使用用户名和密码访问Windows中的用户帐户的LogonUser
API 是- 这是一个Win32本机API.目前没有用于调用它的内置.NET API,因此必须使用P/Invoke.
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);
这是基本的调用定义,但是在生产中实际使用它还有很多需要考虑的事项:
获取具有"安全"访问模式的句柄.
适当地关闭本机句柄
代码访问安全性(CAS)信任级别(仅限.NET Framework中)
路过SecureString
的时候可以通过用户的击键安全地收集一个.
要编写的代码量说明所有这些超出了StackOverflow答案中的应用程序,恕我直言.
不要自己编写所有这些,而是考虑使用我的SimpleImpersonation库,它将模拟和用户访问结合到一个API中.它在现代和旧代码库中运行良好,使用相同的简单API:
var credentials = new UserCredentials(domain, username, password); Impersonation.RunAsUser(credentials, logonType, () => { // do whatever you want as this user. });
要么
var credentials = new UserCredentials(domain, username, password); var result = Impersonation.RunAsUser(credentials, logonType, () => { // do whatever you want as this user. return something; });
请注意,它与WindowsIdentity.RunImpersonated
API 非常相似,但不要求您了解有关令牌句柄的任何信息.
这是从3.0.0版开始的API.有关详细信息,请参阅项目自述文件.另请注意,该库的先前版本使用了具有该IDisposable
模式的API ,类似于WindowsIdentity.Impersonate
.较新版本更安全,两者仍在内部使用.
以下是.NET模拟概念的一些很好的概述.
Michiel van Otegem:WindowsImpersonationContext变得简单
WindowsIdentity.Impersonate方法(查看代码示例)
基本上,您将利用.NET框架中开箱即用的这些类:
WindowsImpersonationContext
的WindowsIdentity
代码通常会变得冗长,这就是为什么你会看到很多例子,比如你引用的那些试图简化过程的例子.
这可能是你想要的:
using System.Security.Principal; using(WindowsIdentity.GetCurrent().Impersonate()) { //your code goes here }
但我真的需要更多细节来帮助你.您可以使用配置文件进行模拟(如果您尝试在网站上执行此操作),或者通过方法装饰器(属性)进行模拟(如果它是WCF服务),或者通过...来实现.
此外,如果我们正在讨论模仿调用特定服务(或Web应用程序)的客户端,则需要正确配置客户端,以便它传递适当的令牌.
最后,如果你真正想做的是委托,你还需要正确设置AD,以便用户和机器可以进行委派.
编辑:
看看这里,看看如何冒充不同的用户,以及进一步的文档.
这是我的马特约翰逊的vb.net端口的答案.我为登录类型添加了一个枚举.LOGON32_LOGON_INTERACTIVE
是第一个适用于sql server的枚举值.我的连接字符串只是受信任的.连接字符串中没有用户名/密码.
_
Public Class Impersonation
Implements IDisposable
Public Enum LogonTypes
'''
''' This logon type is intended for users who will be interactively using the computer, such as a user being logged on
''' by a terminal server, remote shell, or similar process.
''' This logon type has the additional expense of caching logon information for disconnected operations;
''' therefore, it is inappropriate for some client/server applications,
''' such as a mail server.
'''
LOGON32_LOGON_INTERACTIVE = 2
'''
''' This logon type is intended for high performance servers to authenticate plaintext passwords.
''' The LogonUser function does not cache credentials for this logon type.
'''
LOGON32_LOGON_NETWORK = 3
'''
''' This logon type is intended for batch servers, where processes may be executing on behalf of a user without
''' their direct intervention. This type is also for higher performance servers that process many plaintext
''' authentication attempts at a time, such as mail or Web servers.
''' The LogonUser function does not cache credentials for this logon type.
'''
LOGON32_LOGON_BATCH = 4
'''
''' Indicates a service-type logon. The account provided must have the service privilege enabled.
'''
LOGON32_LOGON_SERVICE = 5
'''
''' This logon type is for GINA DLLs that log on users who will be interactively using the computer.
''' This logon type can generate a unique audit record that shows when the workstation was unlocked.
'''
LOGON32_LOGON_UNLOCK = 7
'''
''' This logon type preserves the name and password in the authentication package, which allows the server to make
''' connections to other network servers while impersonating the client. A server can accept plaintext credentials
''' from a client, call LogonUser, verify that the user can access the system across the network, and still
''' communicate with other servers.
''' NOTE: Windows NT: This value is not supported.
'''
LOGON32_LOGON_NETWORK_CLEARTEXT = 8
'''
''' This logon type allows the caller to clone its current token and specify new credentials for outbound connections.
''' The new logon session has the same local identifier but uses different credentials for other network connections.
''' NOTE: This logon type is supported only by the LOGON32_PROVIDER_WINNT50 logon provider.
''' NOTE: Windows NT: This value is not supported.
'''
LOGON32_LOGON_NEW_CREDENTIALS = 9
End Enum
_
Private Shared Function LogonUser(lpszUsername As [String], lpszDomain As [String], lpszPassword As [String], dwLogonType As Integer, dwLogonProvider As Integer, ByRef phToken As SafeTokenHandle) As Boolean
End Function
Public Sub New(Domain As String, UserName As String, Password As String, Optional LogonType As LogonTypes = LogonTypes.LOGON32_LOGON_INTERACTIVE)
Dim ok = LogonUser(UserName, Domain, Password, LogonType, 0, _SafeTokenHandle)
If Not ok Then
Dim errorCode = Marshal.GetLastWin32Error()
Throw New ApplicationException(String.Format("Could not impersonate the elevated user. LogonUser returned error code {0}.", errorCode))
End If
WindowsImpersonationContext = WindowsIdentity.Impersonate(_SafeTokenHandle.DangerousGetHandle())
End Sub
Private ReadOnly _SafeTokenHandle As New SafeTokenHandle
Private ReadOnly WindowsImpersonationContext As WindowsImpersonationContext
Public Sub Dispose() Implements System.IDisposable.Dispose
Me.WindowsImpersonationContext.Dispose()
Me._SafeTokenHandle.Dispose()
End Sub
Public NotInheritable Class SafeTokenHandle
Inherits SafeHandleZeroOrMinusOneIsInvalid
_
_
_
Private Shared Function CloseHandle(handle As IntPtr) As Boolean
End Function
Public Sub New()
MyBase.New(True)
End Sub
Protected Overrides Function ReleaseHandle() As Boolean
Return CloseHandle(handle)
End Function
End Class
End Class
您需要使用Using
语句来包含一些代码来运行模拟.