C# PrincipalContext.ValidateCredentials始终返回FALSE

C# PrincipalContext.ValidateCredentials始终返回FALSE,c#,asp.net-mvc,active-directory,activedirectorymembership,C#,Asp.net Mvc,Active Directory,Activedirectorymembership,我有一个MVC应用程序,需要登录并根据Active Directory验证用户。我正在使用PrincipalContext.ValidateCredentials方法,但总是得到false的身份验证 连接到服务器很好。问题似乎出现在ValidateCredentials中 这是我的密码: public static bool IsAuthenticated(string domain, string username, string pwd) { bool IsAuthenticated

我有一个MVC应用程序,需要登录并根据Active Directory验证用户。我正在使用
PrincipalContext.ValidateCredentials
方法,但总是得到
false
的身份验证

连接到服务器很好。问题似乎出现在
ValidateCredentials

这是我的密码:

public static bool IsAuthenticated(string domain, string username, string pwd) {
    bool IsAuthenticated = false;

    try {
        PrincipalContext insPrincipalContext = 
            new PrincipalContext(ContextType.Domain, domain, "DC=c1w,DC=com");

        username = "c1w\\" + username;

        IsAuthenticated = insPrincipalContext.ValidateCredentials(username, pwd);
    }
    catch (Exception ex)
    {
        // Rethrow this exception
        ExceptionPolicy.HandleException(ex, "Exception Policy");
    }

    return IsAuthenticated;
}

有人知道为什么会发生这种情况吗?

我不知道在哪里初始化“pwd”变量
也许您应该在这个方法中使用它来精确地指定所需的行为。很抱歉回答太多,但您的问题中没有太多细节

您似乎正在使用域\用户名格式验证用户。您可能需要从用户名和用户ValidateCredential解析域名。

以下是
ValidateCredentials(string,string)
的工作原理:首先,它尝试使用
协商
签名
密封
上下文选项进行身份验证。如果失败,它将使用
SimpleBind
SecureSocketLayer
重试

问题在于NT4(又名“遗留”,又名“下层名称”)格式(
DOMAIN\UserName
,或者更准确地说,
NetBiosName\SamAccountName
)无法与协商一起工作。但它确实适用于SimpleBind

因此,调用2参数
ValidateCredentials()
方法时可能发生的情况是,它首先使用协商失败,因为它不喜欢NT4格式,然后在使用简单绑定时再次失败

在我自己的测试过程中,我发现即使在回到使用简单绑定之后,它仍然失败的原因是它不仅使用了SimpleBind。它使用的是
SimpleBind
plus
SecureSocketLayer
。这意味着,如果Active Directory服务器未正确设置为使用SSL(测试环境的常见场景),它仍将失败

正如其中一条评论中提到的,您永远都不想单独使用
SimpleBind
(没有
SecureSocketLayer
),否则您的密码将通过网络以纯文本形式发送

在野外,我看到一些Active Directory系统根本不允许使用简单绑定,因此您必须让它与协商一起工作

我找到了两种解决此问题的方法:

1) 如果所有事情都发生在同一个域上,那么您应该能够只使用用户名(SAM帐户名)调用
ValidateCredentials
,而不使用“域”部分。然后,它将在第一次使用协商时正常工作


2) 如果域部分很重要,因为可能涉及多个域(即
Domain1\UserA
Domain2\UserA
是不同的人),那么它会变得更复杂一些。在本例中,我最终将NT4名称(域\用户)转换为“用户主体名称”格式(例如
LogonName@domain.com
)。有两种不同的方法可以做到这一点。最简单的方法可能是使用
UserPrincipal.FindByIdentity()
的3参数重载,然后获取结果的
UserPrincipalName
属性的值。另一种方法是使用
DirectorySearcher
并使用匹配的
sAMAccountName
值查询用户的
userPrincipalName
属性。注意:只有当所有涉及的域都在同一个林中时,此解决方案才会起作用。

编辑了该问题以包括整个方法。将尝试ContextOption建议。谢谢。B-Rain,ContextOption参考为我指明了正确的方向。最后使用了ContextOptions。在我调用AD和ContextOptions.SimpleBind时协商验证凭据。简单绑定将为我工作,因为该网站将是SSL安全的。谢谢你的帮助。我对问题和答案都投了赞成票,因为这对我的处境也有帮助。在我的例子中,我的开发机器(登录时不指定上下文)位于网络上的安全区域,但web服务器(登录时不指定上下文)位于DMZ中。我使用了与@Billy Logan相同的配置—在对AD的调用中进行协商,在验证调用中使用SimpleBind。那么您使用了什么?ContextOptions.Congregate或ContextOptions.SimpleBind?如果使用ContextOptions.SimpleBind,请注意密码可能以明文形式通过网络发送。