活动目录 - 检查用户名/密码

34

我在Windows Vista Ultimate SP1上使用以下代码查询我们的活动目录服务器,以检查域中用户的用户名和密码。

public Object IsAuthenticated()
{
    String domainAndUsername = strDomain + "\\" + strUser;
    DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, strPass);
    SearchResult result;
    try
    {
        //Bind to the native AdsObject to force authentication.         

        DirectorySearcher search = new DirectorySearcher(entry) { Filter = ("(SAMAccountName=" + strUser + ")") };

        search.PropertiesToLoad.Add("givenName"); // First Name                
        search.PropertiesToLoad.Add("sn"); // Last Name
        search.PropertiesToLoad.Add("cn"); // Last Name

        result = search.FindOne();

        if (null == result)
        {
            return null;
        }

        //Update the new path to the user in the directory.
        _path = result.Path;
        _filterAttribute = (String)result.Properties["cn"][0];
    }
    catch (Exception ex)
    {
        return new Exception("Error authenticating user. " + ex.Message);
    }
    return user;
}

目标使用的是.NET 3.5,并且是使用VS 2008标准版编译的。

我以应用程序运行的域帐户登录,该帐户是域管理员。

代码在Windows XP上完美运行;但是在Vista上运行时出现以下异常:

System.DirectoryServices.DirectoryServicesCOMException (0x8007052E): Logon failure: unknown user name or bad password.

   at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
   at System.DirectoryServices.DirectoryEntry.Bind()
   at System.DirectoryServices.DirectoryEntry.get_AdsObject()
   at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
   at System.DirectoryServices.DirectorySearcher.FindOne()
   at Chain_Of_Custody.Classes.Authentication.LdapAuthentication.IsAuthenticated()
   at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
   at System.DirectoryServices.DirectoryEntry.Bind()
   at System.DirectoryServices.DirectoryEntry.get_AdsObject()
   at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
   at System.DirectoryServices.DirectorySearcher.FindOne()
   at Chain_Of_Custody.Classes.Authentication.LdapAuthentication.IsAuthenticated()

我已经尝试更改认证类型,但不确定出了什么问题。


另请参阅: 如何验证用户名和密码是否与Active Directory匹配?


这真的是完全重复吗?这个人收到了一个异常消息,而不是在问如何做... - hugoware
由于您正在使用.NET 3.5,因此您可以选择使用System.DirectoryServices.AccountManagement。我在工作中没有使用Vista,但由于这是针对3.5的,它可能与Vista更兼容... - hugoware
我不会称这为重复... - cgreeno
我总算想通了如果你在Vista上使用“domain\user”格式传递域和用户名,它是无法工作的。所以只传递“user”似乎可以正常工作 - 但前提是你必须在同一个域中。 - Michael G
4个回答

50

如果你正在使用 .net 3.5,请使用以下代码。

验证用户身份:

PrincipalContext adContext = new PrincipalContext(ContextType.Domain);

using (adContext)
{
     return adContext.ValidateCredentials(UserName, Password);
}

如果你需要找到可以读写对象属性的用户,请执行以下操作:

PrincipalContext context = new PrincipalContext(ContextType.Domain);
UserPrincipal foundUser = 
    UserPrincipal.FindByIdentity(context, "jdoe");

这里使用了System.DirectoryServices.AccountManagement命名空间,所以您需要将其添加到您的using声明中。

如果您需要将UserPrincipal对象转换为DirectoryEntry对象以便与旧代码一起使用,可以这样做:

DirectoryEntry userDE = (DirectoryEntry)foundUser.GetUnderlyingObject();

嗨@steve,你的意思是我们在定义主体上下文时不需要给出域名吗?那么它将如何知道要针对哪个域进行验证?此外,你能否指点一下文档,我找不到它。 - User16119012

8

我发现同样的代码在多个网站上都有,但是对我来说并没有用。Steve Evans可能是正确的,如果你正在使用.NET 3.5,你不应该使用这段代码。但是如果你仍然在使用.NET 2.0,你可以尝试使用以下代码来进行AD服务的身份验证:

DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain, 
   userName, password, 
   AuthenticationTypes.Secure | AuthenticationTypes.SecureSocketsLayer);
object nativeObject = entry.NativeObject;

第一行使用域、用户名和密码创建了一个DirectoryEntry对象。它还设置了AuthenticationTypes。请注意,我在两个参数之间使用“按位或”('|')运算符来同时设置安全(Kerberos)身份验证和SSL。
第二行强制“entry”的NativeObject使用第一行的信息绑定到AD服务。
如果抛出异常,则证书(或设置)有误。如果没有异常,则您已经通过身份验证。异常消息通常会指示出错原因。
这段代码与您已经拥有的代码非常相似,但是我们使用了域名,而您使用的是“path”,而且用户名没有与域名组合。请确保正确设置AuthenticationTypes,这可能会影响身份验证的能力。

这个问题涉及到的是 .Net 3.5;而不是 .Net 2.0。 - jww
1
这是我看到的第一个结合了Secure和SecureSocketsLayer标志的答案,这也是我设法使其工作的唯一方法。谢谢! - EricRRichards

1

我终于想通了。如果你在Vista上使用带有用户名的域名“domain\user”,它不起作用,所以只传递“user”似乎可以正常工作 - 除非你在同一个域中。


您应该能够通过使用user@domain的方式来更改域。 - Andrew Cox

0

绑定LDAP是否需要提升特权(UAC)?您可以尝试以管理员身份运行Visual Studio和/或应用程序,看看是否有帮助。如果这是问题,您可以始终向应用程序添加清单并将其设置为需要提升,这样它将在用户运行时提示。

不确定为什么需要提升特权,但值得一试。


以管理员身份运行并不能解决问题。 - Michael G

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接