如何对活动目录验证用户名和密码?我只是想检查用户名和密码是否正确。


当前回答

使用DirectoryServices非常简单的解决方案:

using System.DirectoryServices;

//srvr = ldap server, e.g. 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:

用户需要在下次登录时更改密码。 用户密码已过期。

ActiveDirectory不允许您使用LDAP来确定密码是否由于用户必须更改密码或密码是否过期而无效。

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

Error_password_must_change = 1907 Error_password_expired = 1330

如果你使用的是。net 3.5或更新版本,你可以使用System.DirectoryServices.AccountManagement命名空间轻松验证你的凭证:

// create a "principal context" - e.g. 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#托管代码——你还能要求什么呢?: -)

在这里阅读所有内容:

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

更新:

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

可能最简单的方法是PInvoke LogonUser Win32 api。

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

MSDN参考在这里…

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

绝对要使用登录类型

LOGON32_LOGON_NETWORK (3)

这只创建了一个轻量级的令牌-完美的认证检查。(其他类型可用于构建交互式会话等)

对我来说,这两个下面的工作,确保你的域名是LDAP://在开始

//"LDAP://" + domainName
private void btnValidate_Click(object sender, RoutedEventArgs e)
{
    try
    {
        DirectoryEntry de = new DirectoryEntry(txtDomainName.Text, txtUsername.Text, txtPassword.Text);
        DirectorySearcher dsearch = new DirectorySearcher(de);
        SearchResult results = null;

        results = dsearch.FindOne();

        MessageBox.Show("Validation Success.");
    }
    catch (LdapException ex)
    {
        MessageBox.Show($"Validation Failure. {ex.GetBaseException().Message}");
    }
    catch (Exception ex)
    {
        MessageBox.Show($"Validation Failure. {ex.GetBaseException().Message}");
    }
}

private void btnValidate2_Click(object sender, RoutedEventArgs e)
{
    try
    {
        LdapConnection lcon = new LdapConnection(new LdapDirectoryIdentifier((string)null, false, false));
        NetworkCredential nc = new NetworkCredential(txtUsername.Text,
                               txtPassword.Text, txtDomainName.Text);
        lcon.Credential = nc;
        lcon.AuthType = AuthType.Negotiate;
        lcon.Bind(nc);

        MessageBox.Show("Validation Success.");
    }
    catch (LdapException ex)
    {
        MessageBox.Show($"Validation Failure. {ex.GetBaseException().Message}");
    }
    catch (Exception ex)
    {
        MessageBox.Show($"Validation Failure. {ex.GetBaseException().Message}");
    }
}

如果你被。net 2.0和托管代码困住了,这里有另一种处理本地和域帐户的方法:

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