当前位置:  开发笔记 > 编程语言 > 正文

你如何在.NET中进行模拟?

如何解决《你如何在.NET中进行模拟?》经验,为你挑选了4个好方法。

是否有一种简单的开箱即用方式来模拟.NET中的用户?

到目前为止,我一直在代码项目中使用这个类来满足我的所有模拟要求.

有没有更好的方法来使用.NET Framework?

我有一个用户凭据集(用户名,密码,域名),表示我需要模拟的身份.



1> Matt Johnson..:

.NET空间中的"模拟"通常意味着在特定用户帐户下运行代码.这是一个有点单独的概念,而不是通过用户名和密码访问该用户帐户,尽管这两个想法经常配对.我将描述它们,然后解释如何使用我的SimpleImpersonation库,它在内部使用它们.

模拟

用于模拟的API通过System.Security.Principal命名空间在.NET中提供:

通常应使用较新的代码(.NET 4.6 +,.NET Core等)WindowsIdentity.RunImpersonated,它接受用户帐户令牌的句柄,然后接受ActionFunc执行代码.

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中的用户帐户的LogonUserAPI 是- 这是一个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.RunImpersonatedAPI 非常相似,但不要求您了解有关令牌句柄的任何信息.

这是从3.0.0版开始的API.有关详细信息,请参阅项目自述文件.另请注意,该库的先前版本使用了具有该IDisposable模式的API ,类似于WindowsIdentity.Impersonate.较新版本更安全,两者仍在内部使用.


这与http://msdn.microsoft.com/en-us/library/system.security.principal.windowsimpersonationcontext.aspx上提供的代码非常相似,但是看到这里列出的所有内容都非常棒.简单明了,易于整合到我的解决方案中.非常感谢您做了所有艰苦的工作!
@Sophit - [这里的参考源代码](http://referencesource.microsoft.com/#mscorlib/system/security/principal/windowsimpersonationcontext.cs#134)清楚地显示在处理过程中调用`Undo`.
@Chris - 您需要使用其他登录类型之一.类型9仅提供对出站网络凭据的模拟.我从WinForms应用程序测试了类型2,3和8,他们正确地更新了当前的主体.人们会假设类型4和5也适用于服务或批量应用.请参阅我在帖子中引用的链接.
@Sophit - [已经有](http://referencesource.microsoft.com/#mscorlib/system/security/principal/windowsimpersonationcontext.cs#134).

2> Eric Schoono..:

以下是.NET模拟概念的一些很好的概述.

Michiel van Otegem:WindowsImpersonationContext变得简单

WindowsIdentity.Impersonate方法(查看代码示例)

基本上,您将利用.NET框架中开箱即用的这些类:

WindowsImpersonationContext

的WindowsIdentity

代码通常会变得冗长,这就是为什么你会看到很多例子,比如你引用的那些试图简化过程的例子.


只是注意假冒不是银弹,而有些API根本不适合模仿.

3> Esteban Aray..:

这可能是你想要的:

using System.Security.Principal;
using(WindowsIdentity.GetCurrent().Impersonate())
{
     //your code goes here
}

但我真的需要更多细节来帮助你.您可以使用配置文件进行模拟(如果您尝试在网站上执行此操作),或者通过方法装饰器(属性)进行模拟(如果它是WCF服务),或者通过...来实现.

此外,如果我们正在讨论模仿调用特定服务(或Web应用程序)的客户端,则需要正确配置客户端,以便它传递适当的令牌.

最后,如果你真正想做的是委托,你还需要正确设置AD,以便用户和机器可以进行委派.

编辑:
看看这里,看看如何冒充不同的用户,以及进一步的文档.


此代码看起来只能模拟当前窗口标识.有没有办法获取另一个用户的WindowsIdentity对象?

4> toddmo..:

这是我的马特约翰逊的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语句来包含一些代码来运行模拟.

推荐阅读
女女的家_747
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有