Wie kann ich einen Benutzernamen und ein Passwort mit Active Directory abgleichen? Ich möchte einfach prüfen, ob ein Benutzername und ein Kennwort korrekt sind.
Antworten
Zu viele Anzeigen?Der wahrscheinlich einfachste Weg ist der PInvoke LogonUser Win32 API.z.B.
MSDN-Referenz hier...
Definitiv den Anmeldetyp verwenden wollen
LOGON32_LOGON_NETWORK (3)
Dadurch wird nur ein leichtes Token erstellt - perfekt für AuthN-Prüfungen. (andere Typen können zum Aufbau interaktiver Sitzungen usw. verwendet werden)
Eine vollständige .Net-Lösung ist die Verwendung der Klassen aus dem System.DirectoryServices-Namensraum. Sie ermöglichen die direkte Abfrage eines AD-Servers. Hier ist ein kleines Beispiel, das dies tun würde:
using (DirectoryEntry entry = new DirectoryEntry())
{
entry.Username = "here goes the username you want to validate";
entry.Password = "here goes the password";
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.Filter = "(objectclass=user)";
try
{
searcher.FindOne();
}
catch (COMException ex)
{
if (ex.ErrorCode == -2147023570)
{
// Login or password is incorrect
}
}
}
// FindOne() didn't throw, the credentials are correct
Dieser Code stellt eine direkte Verbindung zum AD-Server her, wobei die angegebenen Anmeldeinformationen verwendet werden. Wenn die Anmeldeinformationen ungültig sind, löst searcher.FindOne() eine Ausnahme aus. Der ErrorCode ist derjenige, der dem COM-Fehler "ungültiger Benutzername/Passwort" entspricht.
Sie müssen den Code nicht als AD-Benutzer ausführen. Ich habe ihn sogar erfolgreich zur Abfrage von Informationen auf einem AD-Server von einem Client außerhalb der Domäne aus verwendet!
Ein weiterer .NET-Aufruf zur schnellen Authentifizierung von LDAP-Anmeldeinformationen:
using System.DirectoryServices;
using(var DE = new DirectoryEntry(path, username, password)
{
try
{
DE.RefreshCache(); // This will force credentials validation
}
catch (COMException ex)
{
// Validation failed - handle how you want
}
}
Versuchen Sie diesen Code (HINWEIS: Es wurde berichtet, dass es unter Windows Server 2000 nicht funktioniert)
#region NTLogonUser
#region Direct OS LogonUser Code
[DllImport( "advapi32.dll")]
private static extern bool LogonUser(String lpszUsername,
String lpszDomain, String lpszPassword, int dwLogonType,
int dwLogonProvider, out int phToken);
[DllImport("Kernel32.dll")]
private static extern int GetLastError();
public static bool LogOnXP(String sDomain, String sUser, String sPassword)
{
int token1, ret;
int attmpts = 0;
bool LoggedOn = false;
while (!LoggedOn && attmpts < 2)
{
LoggedOn= LogonUser(sUser, sDomain, sPassword, 3, 0, out token1);
if (LoggedOn) return (true);
else
{
switch (ret = GetLastError())
{
case (126): ;
if (attmpts++ > 2)
throw new LogonException(
"Specified module could not be found. error code: " +
ret.ToString());
break;
case (1314):
throw new LogonException(
"Specified module could not be found. error code: " +
ret.ToString());
case (1326):
// edited out based on comment
// throw new LogonException(
// "Unknown user name or bad password.");
return false;
default:
throw new LogonException(
"Unexpected Logon Failure. Contact Administrator");
}
}
}
return(false);
}
#endregion Direct Logon Code
#endregion NTLogonUser
außer dass Sie Ihre eigene benutzerdefinierte Ausnahme für "LogonException" erstellen müssen
Die Windows-Authentifizierung kann aus verschiedenen Gründen fehlschlagen: ein falscher Benutzername oder ein falsches Kennwort, ein gesperrtes Konto, ein abgelaufenes Kennwort und vieles mehr. Um zwischen diesen Fehlern zu unterscheiden, rufen Sie den LogonUser API-Funktion über P/Invoke und prüfen Sie den Fehlercode, wenn die Funktion zurückgibt false
:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
public static class Win32Authentication
{
private class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeTokenHandle() // called by P/Invoke
: base(true)
{
}
protected override bool ReleaseHandle()
{
return CloseHandle(this.handle);
}
}
private enum LogonType : uint
{
Network = 3, // LOGON32_LOGON_NETWORK
}
private enum LogonProvider : uint
{
WinNT50 = 3, // LOGON32_PROVIDER_WINNT50
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser(
string userName, string domain, string password,
LogonType logonType, LogonProvider logonProvider,
out SafeTokenHandle token);
public static void AuthenticateUser(string userName, string password)
{
string domain = null;
string[] parts = userName.Split('\\');
if (parts.Length == 2)
{
domain = parts[0];
userName = parts[1];
}
SafeTokenHandle token;
if (LogonUser(userName, domain, password, LogonType.Network, LogonProvider.WinNT50, out token))
token.Dispose();
else
throw new Win32Exception(); // calls Marshal.GetLastWin32Error()
}
}
Beispielhafte Verwendung:
try
{
Win32Authentication.AuthenticateUser("EXAMPLE\\user", "P@ssw0rd");
// Or: Win32Authentication.AuthenticateUser("user@example.com", "P@ssw0rd");
}
catch (Win32Exception ex)
{
switch (ex.NativeErrorCode)
{
case 1326: // ERROR_LOGON_FAILURE (incorrect user name or password)
// ...
case 1327: // ERROR_ACCOUNT_RESTRICTION
// ...
case 1330: // ERROR_PASSWORD_EXPIRED
// ...
case 1331: // ERROR_ACCOUNT_DISABLED
// ...
case 1907: // ERROR_PASSWORD_MUST_CHANGE
// ...
case 1909: // ERROR_ACCOUNT_LOCKED_OUT
// ...
default: // Other
break;
}
}
Hinweis: LogonUser erfordert eine Vertrauensbeziehung mit der Domäne, für die Sie die Gültigkeit überprüfen.