是否有一种简单的开箱即用的方法来模拟.NET中的用户?
使用.NET Framework是否有更好的方法呢?
我有一个用户凭据集(用户名,密码,域名),它代表我需要模拟的身份。
是否有一种简单的开箱即用的方法来模拟.NET中的用户?
使用.NET Framework是否有更好的方法呢?
我有一个用户凭据集(用户名,密码,域名),它代表我需要模拟的身份。
Answers:
.NET空间中的“模拟”通常意味着在特定用户帐户下运行代码。尽管这两个主意经常结合在一起,但与通过用户名和密码访问该用户帐户相比,这是一个与众不同的概念。我将描述它们,然后解释如何使用内部使用它们的SimpleImpersonation库。
.NET通过System.Security.Principal
名称空间提供用于模拟的API :
较新的代码(.NET 4.6 + 、. NET Core等)通常应使用WindowsIdentity.RunImpersonated
,该代码接受用户帐户令牌的句柄,然后接受Action
或Func<T>
以便代码执行。
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中仍然存在,但通常应避免使用该API,并且在.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);
这是基本的调用定义,但是在生产中实际使用它还有很多要考虑的因素:
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。有关更多详细信息,请参见项目自述文件。另请注意,该库的先前版本使用的API带有IDisposable
模式,类似于WindowsIdentity.Impersonate
。较新的版本更安全,并且两者仍在内部使用。
这可能是您想要的:
using System.Security.Principal;
using(WindowsIdentity.GetCurrent().Impersonate())
{
//your code goes here
}
但是我真的需要更多细节来帮助您。您可以使用配置文件(如果要在网站上进行此操作)进行模拟,或者如果它是WCF服务,则可以通过方法装饰器(属性)进行模拟,或者通过...您就可以了。
另外,如果我们要假冒模拟称为特定服务(或Web应用程序)的客户端,则需要正确配置客户端,以使其传递适当的令牌。
最后,如果您真正想要做的是委派,则还需要正确设置AD,以便信任用户和计算机进行委派。
编辑:
请看这里以了解如何模拟其他用户,以及更多文档。
这是我对Matt Johnson的答复的vb.net端口。我为登录类型添加了一个枚举。LOGON32_LOGON_INTERACTIVE
是适用于sql server的第一个枚举值。我的连接字符串是可信的。连接字符串中没有用户名/密码。
<PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
Public Class Impersonation
Implements IDisposable
Public Enum LogonTypes
''' <summary>
''' 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.
''' </summary>
LOGON32_LOGON_INTERACTIVE = 2
''' <summary>
''' This logon type is intended for high performance servers to authenticate plaintext passwords.
''' The LogonUser function does not cache credentials for this logon type.
''' </summary>
LOGON32_LOGON_NETWORK = 3
''' <summary>
''' 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.
''' </summary>
LOGON32_LOGON_BATCH = 4
''' <summary>
''' Indicates a service-type logon. The account provided must have the service privilege enabled.
''' </summary>
LOGON32_LOGON_SERVICE = 5
''' <summary>
''' 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.
''' </summary>
LOGON32_LOGON_UNLOCK = 7
''' <summary>
''' 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.
''' </summary>
LOGON32_LOGON_NETWORK_CLEARTEXT = 8
''' <summary>
''' 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.
''' </summary>
LOGON32_LOGON_NEW_CREDENTIALS = 9
End Enum
<DllImport("advapi32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
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
<DllImport("kernel32.dll")> _
<ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)> _
<SuppressUnmanagedCodeSecurity()> _
Private Shared Function CloseHandle(handle As IntPtr) As <MarshalAs(UnmanagedType.Bool)> 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
语句一起使用,以包含一些模拟运行的代码。
查看上一个答案的更多详细信息,我创建了一个nuget包 Nuget
Github上的代码
示例:您可以使用:
string login = "";
string domain = "";
string password = "";
using (UserImpersonation user = new UserImpersonation(login, domain, password))
{
if (user.ImpersonateValidUser())
{
File.WriteAllText("test.txt", "your text");
Console.WriteLine("File writed");
}
else
{
Console.WriteLine("User not connected");
}
}
Vieuw完整代码:
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
/// <summary>
/// Object to change the user authticated
/// </summary>
public class UserImpersonation : IDisposable
{
/// <summary>
/// Logon method (check athetification) from advapi32.dll
/// </summary>
/// <param name="lpszUserName"></param>
/// <param name="lpszDomain"></param>
/// <param name="lpszPassword"></param>
/// <param name="dwLogonType"></param>
/// <param name="dwLogonProvider"></param>
/// <param name="phToken"></param>
/// <returns></returns>
[DllImport("advapi32.dll")]
private static extern bool LogonUser(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
/// <summary>
/// Close
/// </summary>
/// <param name="handle"></param>
/// <returns></returns>
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
private WindowsImpersonationContext _windowsImpersonationContext;
private IntPtr _tokenHandle;
private string _userName;
private string _domain;
private string _passWord;
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
/// <summary>
/// Initialize a UserImpersonation
/// </summary>
/// <param name="userName"></param>
/// <param name="domain"></param>
/// <param name="passWord"></param>
public UserImpersonation(string userName, string domain, string passWord)
{
_userName = userName;
_domain = domain;
_passWord = passWord;
}
/// <summary>
/// Valiate the user inforamtion
/// </summary>
/// <returns></returns>
public bool ImpersonateValidUser()
{
bool returnValue = LogonUser(_userName, _domain, _passWord,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
ref _tokenHandle);
if (false == returnValue)
{
return false;
}
WindowsIdentity newId = new WindowsIdentity(_tokenHandle);
_windowsImpersonationContext = newId.Impersonate();
return true;
}
#region IDisposable Members
/// <summary>
/// Dispose the UserImpersonation connection
/// </summary>
public void Dispose()
{
if (_windowsImpersonationContext != null)
_windowsImpersonationContext.Undo();
if (_tokenHandle != IntPtr.Zero)
CloseHandle(_tokenHandle);
}
#endregion
}
我知道我参加聚会已经很晚了,但是我认为Phillip Allan-Harding的图书馆是这种情况下和类似情况下最好的图书馆。
您只需要一小段这样的代码:
private const string LOGIN = "mamy";
private const string DOMAIN = "mongo";
private const string PASSWORD = "HelloMongo2017";
private void DBConnection()
{
using (Impersonator user = new Impersonator(LOGIN, DOMAIN, PASSWORD, LogonType.LOGON32_LOGON_NEW_CREDENTIALS, LogonProvider.LOGON32_PROVIDER_WINNT50))
{
}
}
并添加他的课程:
如果您要求模拟登录具有网络凭据,但是可以使用更多示例,则可以使用我的示例。
您可以使用此解决方案。(使用nuget包)源代码位于:Github:https : //github.com/michelcedric/UserImpersonation
更多详细信息 https://michelcedric.wordpress.com/2015/09/03/usurpation-didentite-dun-user-c-user-impersonation/