根据Active Directoryvalidation用户名和密码?

我如何根据Active Directoryvalidation用户名和密码? 我只是想检查用户名和密码是否正确。

如果您使用.NET 3.5或更高版本,则可以使用System.DirectoryServices.AccountManagement命名空间并轻松validation您的凭据:

 // create a "principal context" - eg your domain (could be machine, too) using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "YOURDOMAIN")) { // validate the credentials bool isValid = pc.ValidateCredentials("myuser", "mypassword"); } 

这很简单,它是可靠的,它是100%C#托pipe代码在你的最终 – 你还能要求什么? 🙂

在这里阅读所有信息:

  • pipe理.NET Framework 3.5中的目录安全主体
  • System.DirectoryServices.AccountManagement上的MSDN文档

更新:

正如在这个其他SO问题(及其答案)中概述的, 这个调用可能返回一个用户的旧密码为True的问题。 只要知道这种行为,不要太惊讶,如果发生这种情况:-)(感谢@MikeGledhill指出这一点!)

我们在我们的内联网上这样做

你必须使用System.DirectoryServices;

这里是代码的胆量

 using (DirectoryEntry adsEntry = new DirectoryEntry(path, strAccountId, strPassword)) { using (DirectorySearcher adsSearcher = new DirectorySearcher(adsEntry)) { //adsSearcher.Filter = "(&(objectClass=user)(objectCategory=person))"; adsSearcher.Filter = "(sAMAccountName=" + strAccountId + ")"; try { SearchResult adsSearchResult = adsSearcher.FindOne(); bSucceeded = true; strAuthenticatedBy = "Active Directory"; strError = "User has been authenticated by Active Directory."; } catch (Exception ex) { // Failed to authenticate. Most likely it is caused by unknown user // id or bad strPassword. strError = ex.Message; } finally { adsEntry.Close(); } } } 

这里提出的几个解决scheme缺乏区分错误的用户/密码和需要改变的密码的能力。 这可以通过以下方式完成:

 using System; using System.DirectoryServices.Protocols; using System.Net; namespace ProtocolTest { class Program { static void Main(string[] args) { try { LdapConnection connection = new LdapConnection("ldap.fabrikam.com"); NetworkCredential credential = new NetworkCredential("user", "password"); connection.Credential = credential; connection.Bind(); Console.WriteLine("logged in"); } catch (LdapException lexc) { String error = lexc.ServerErrorMessage; Console.WriteLine(lexc); } catch (Exception exc) { Console.WriteLine(exc); } } } } 

如果用户密码错误,或者用户不存在,则会包含错误

“8009030C:LdapErr:DSID-0C0904DC,注释:AcceptSecurityContext错误,数据52e,v1db1”,

如果用户密码需要更改,则会包含该密码

“8009030C:LdapErr:DSID-0C0904DC,注释:AcceptSecurityContext错误,数据773,v1db1”

lexc.ServerErrorMessage数据值是Win32错误代码的hex表示forms。 这些错误代码将通过调用Win32 LogonUser API调用返回。 下面的列表总结了hex和十进制值的一系列常用值:

 525​ user not found ​(1317) 52e​ invalid credentials ​(1326) 530​ not permitted to logon at this time​ (1328) 531​ not permitted to logon at this workstation​ (1329) 532​ password expired ​(1330) 533​ account disabled ​(1331) 701​ account expired ​(1793) 773​ user must reset password (1907) 775​ user account locked (1909) 

使用DirectoryServices非常简单的解决scheme:

 using System.DirectoryServices; //srvr = ldap server, eg LDAP://domain.com //usr = user name //pwd = user password public bool IsAuthenticated(string srvr, string usr, string pwd) { bool authenticated = false; try { DirectoryEntry entry = new DirectoryEntry(srvr, usr, pwd); object nativeObject = entry.NativeObject; authenticated = true; } catch (DirectoryServicesCOMException cex) { //not authenticated; reason why is in cex } catch (Exception ex) { //not authenticated due to some other exception [this is optional] } return authenticated; } 

需要NativeObject访问来检测不良的用户/密码

不幸的是,没有“简单”的方式来检查AD上的用户凭证。

到目前为止所提出的每一种方法,你都可能得到一个假阴性:一个用户的信用将是有效的,但是AD在某些情况下将返回false:

  • 用户需要在下次login时更改密码。
  • 用户的密码已过期。

ActiveDirectory将不允许您使用LDAP来确定密码是否无效,因为用户必须更改密码或密码已过期。

要确定密码更改或密码已过期,您可以调用Win32:LogonUser(),并检查以下2个常量的Windows错误代码:

  • ERROR_PASSWORD_MUST_CHANGE = 1907
  • ERROR_PASSWORD_EXPIRED = 1330

可能最简单的方法是PInvoke LogonUser Win32 API.eg

http://www.pinvoke.net/default.aspx/advapi32/LogonUser.html

MSDN参考这里…

http://msdn.microsoft.com/en-us/library/aa378184.aspx

绝对要使用logintypes

 LOGON32_LOGON_NETWORK (3) 

这只会创build一个轻量级令牌 – 非常适合AuthN检查。 (其他types可用于构build交互式会话等)

完整的.Net解决scheme是使用System.DirectoryServices名称空间中的类。 它们允许直接查询AD服务器。 这是一个小样本,可以做到这一点:

 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 

此代码使用提供的凭据直接连接到AD服务器。 如果证书无效,searcher.FindOne()将抛出一个exception。 ErrorCode是对应于“无效的用户名/密码”COM错误。

您不需要以AD用户身份运行代码。 事实上,我成功地使用它来查询AD服务器上的信息,从域外的客户端!

又一个.NET调用来快速validationLDAP凭证:

 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 } } 

试试这个代码(注:报告不能在Windows Server 2000上工作)

 #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 

除非您需要为“LogonException”创build您自己的自定义exception

如果你被困在.NET 2.0和托pipe代码中,这是另一种可以运行本地和域帐户的方式:

 using System; using System.Collections.Generic; using System.Text; using System.Security; using System.Diagnostics; static public bool Validate(string domain, string username, string password) { try { Process proc = new Process(); proc.StartInfo = new ProcessStartInfo() { FileName = "no_matter.xyz", CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), UseShellExecute = false, RedirectStandardError = true, RedirectStandardOutput = true, RedirectStandardInput = true, LoadUserProfile = true, Domain = String.IsNullOrEmpty(domain) ? "" : domain, UserName = username, Password = Credentials.ToSecureString(password) }; proc.Start(); proc.WaitForExit(); } catch (System.ComponentModel.Win32Exception ex) { switch (ex.NativeErrorCode) { case 1326: return false; case 2: return true; default: throw ex; } } catch (Exception ex) { throw ex; } return false; } 

我的简单function

  private bool IsValidActiveDirectoryUser(string activeDirectoryServerDomain, string username, string password) { try { DirectoryEntry de = new DirectoryEntry("LDAP://" + activeDirectoryServerDomain, username + "@" + activeDirectoryServerDomain, password, AuthenticationTypes.Secure); DirectorySearcher ds = new DirectorySearcher(de); ds.FindOne(); return true; } catch //(Exception ex) { return false; } } 

Windows身份validation可能因各种原因失败:用户名或密码不正确,帐户被locking,密码过期等等。 要区分这些错误,请通过P / Invoke调用LogonUser API函数,并在函数返回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() } } 

示例用法:

 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; } } 

注意:LogonUser需要与要validation的域名build立信任关系。