Wie tun Sie Identitätswechsel in .NET?
-
02-07-2019 - |
Frage
Gibt es eine einfache aus der Box Möglichkeit, einen Benutzer in .NET zu verkörpern?
Bisher habe ich diese Klasse von Code-Projekt für alle unter Verwendung von meine Identitätswechsel Anforderungen.
Gibt es einen besseren Weg, es zu tun, indem Sie .NET Framework verwenden?
Ich habe einen Benutzer Berechtigungsset, (Benutzername, Passwort, Domain-Namen), die die Identität I zum Imitieren brauchen darstellt.
Lösung
Hier finden Sie einige gute Übersicht über .NET Identitätswechsel Konzepte.
- Michiel van Otegem: WindowsImpersonationContext leicht gemacht
- WindowsIdentity.Impersonate Methode (überprüfen Sie die Codebeispiele aus)
Grundsätzlich werden Sie diese Klassen werden nutzen, die aus der Box in dem .NET-Framework sind:
Der Code kann erhalten oft langwierig, obwohl, und das ist, warum Sie viele Beispiele, wie die, die Sie Referenz zu sehen, die versuchen, den Prozess zu vereinfachen.
Andere Tipps
„Identitätswechsel“ in dem .NET-Raum bedeutet in der Regel Code unter einem bestimmten Benutzerkonto ausgeführt wird. Es ist ein etwas getrenntes Konzept als über einen Benutzername und Passwort Zugriff auf das Benutzerkonto bekommen, obwohl diese beiden Ideen zusammen häufig paaren. Ich werde beschreiben sie beide, und dann erklären, wie mein SimpleImpersonation Bibliothek, die sie intern verwendet.
Identitätswechsel
Die APIs für den Identitätswechsel sind in .NET über den System.Security.Principal
Namespace bereitgestellt:
-
Neuere Code (.NET 4.6+, .NET-Core, etc.) sollten in der Regel verwenden
WindowsIdentity.Impersonate
Verfahren zur Herstellung einesWindowsImpersonationContext
Objekt abzurufen. Dieses Objekt implementiertIDisposable
, so sollte in der Regel aus einemusing
Block aufgerufen werden.using (WindowsImpersonationContext context = WindowsIdentity.Impersonate(tokenHandle)) { // do whatever you want as this user. }
Während diese API existieren noch in .NET Framework, es in der Regel vermieden werden sollte, und ist in .NET Core oder .NET Standard-nicht zur Verfügung.
Zugriff auf das Benutzerkonto
Die API einen Benutzernamen und ein Passwort für die Verwendung von Zugriff auf ein Benutzerkonto in Windows zu gewinnen ist LogonUser
- das ist eine Win32 native API ist. Es ist nicht eine eingebaute in .NET-API für sie anrufen, so dass man zu P / Invoke zurückgreifen müssen.
[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);
Dies ist die grundlegende Anruf Definition, aber es viel mehr ist, um tatsächlich mit ihm in der Produktion zu berücksichtigen:
- Beschaffung einen Griff mit dem „sicheren“ Zugriffsmuster.
- die native schließen Griffe passend
- Codezugriffssicherheit (CAS) Vertrauensebene (in .NET Framework nur)
- Passing
SecureString
, wenn Sie einen sicher über Tastatureingaben der Benutzer sammeln können.
Die Menge an Code zu schreiben, um all dies zu veranschaulichen, ist jenseits dem, was in einer Antwort Stackoverflow sein sollte, IMHO.
Ein kombiniertes und einfacher Ansatz
Anstatt alle diese Texte selbst zu schreiben, sollten Sie meine SimpleImpersonation Bibliothek, die den Zugang Identitätswechsel und Benutzer kombiniert in einer einzigen API. Es funktioniert gut in modernen und älteren Codebasen, mit dem gleichen einfachen API:
var credentials = new UserCredentials(domain, username, password);
Impersonation.RunAsUser(credentials, logonType, () =>
{
// do whatever you want as this user.
});
oder
var credentials = new UserCredentials(domain, username, password);
var result = Impersonation.RunAsUser(credentials, logonType, () =>
{
// do whatever you want as this user.
return something;
});
Beachten Sie, dass es auf die WindowsIdentity.RunImpersonated
API sehr ähnlich ist, aber erfordert nicht Sie etwas über Token-Griffe kennen.
Dies ist die API ab Version 3.0.0. Siehe das Projekt Readme für weitere Details. Beachten Sie auch, dass eine frühere Version der Bibliothek verwendet, um eine API mit dem IDisposable
Muster, ähnlich wie WindowsIdentity.Impersonate
. Die neuere Version ist viel sicherer, und beide sind intern noch verwendet wird.
Dies ist wahrscheinlich das, was Sie wollen:
using System.Security.Principal;
using(WindowsIdentity.GetCurrent().Impersonate())
{
//your code goes here
}
Aber ich brauche wirklich mehr Details um Ihnen zu helfen. Sie könnten mit einer Konfigurationsdatei tun Identitätswechsel (wenn Sie versuchen, diese auf einer Website zu tun hat), oder durch Verfahren Dekorateure (Attribute), wenn es ein WCF-Dienst oder durch ... Sie bekommen die Idee.
Auch wenn wir einen Kunden über Identitätswechsel, die einen bestimmten Dienst (oder Web-App) genannt sprechen, müssen Sie den Client korrekt konfigurieren, dass sie die entsprechenden Token geht.
Wenn schließlich, was Sie wirklich wollen Delegation ist, müssen Sie auch die Einrichtung AD richtig, so dass Benutzer und Maschinen für die Delegierung vertrauenswürdig eingestuft werden.
Bearbeiten
Werfen Sie einen Blick hier , um zu sehen, wie man Identitätswechsel einen anderen Benutzer, und für die weitere Dokumentation.
Hier ist mein vb.net Hafen von Matt Johnson Antwort. Ich habe eine Enumeration für die Anmeldetypen. LOGON32_LOGON_INTERACTIVE
war der erste ENUM-Wert, der für SQL Server gearbeitet. Meine Verbindungszeichenfolge wurde nur vertraut. Kein Benutzername / Kennwort in der Verbindungszeichenfolge.
<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
Sie müssen sich mit einem Using
Anweisung verwenden einige Code enthalten, um imitierte zu laufen.
Weiteres Detail aus meiner früheren Antwort Ich habe ein nuget Paket erstellt Nuget
-Code auf Github
Beispiel: Sie verwenden können:
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 den vollständigen Code:
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
}
Ich bin mir bewusst, dass ich ziemlich spät für die Partei bin, aber ich halte, dass die Bibliothek von Phillip Allan-Harding , es ist die beste für diesen Fall und ähnliche.
Sie brauchen nur ein kleines Stück Code wie diese:
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))
{
}
}
Und fügen Sie seine Klasse:
. NET (C #) Identitätswechsel mit Netzwerkberechtigungen
Mein Beispiel kann verwendet werden, wenn Sie die imitierten-Anmeldung benötigen Netzwerk-Anmeldeinformationen haben, aber es mehr Optionen.
Sie können mit dieser Lösung. (Use NuGet-Paket) Der Quellcode ist verfügbar auf: Github: https://github.com/michelcedric/UserImpersonation
Weitere Einzelheiten https: //michelcedric.wordpress. com / 2015/09/03 / Usurpation-didentite-dun-user-c-Benutzer-Identitätswechsel /