我需要为我的intranet web应用程序创建一个方法,该方法将使用DirectoryServices
对用户进行身份验证,无论是针对默认域还是用户指定的域。
在我的登录表单上,用户可以以"username"
和"password
"或"domainusername"
和"password"
的形式提供凭据第一种情况可以在用户与Web服务器位于同一域并且非常直接的情况下使用。我使用的代码是:
string domain = "";
// Code to check if the username is in form of "domainuser" or "user"
string username = ParseUsername(username, out domain);
if(domain == "")
domain = defaultDomain;
PrincipalContext context = new PrincipalContext(ContextType.Domain, domain, username, password);
bool IsAuthenticated = context.ValidateCredentials(username, password)
我将用户名和密码传递给PrincipalContext构造函数,以便在尝试访问另一个域时绑定调用。
对于本地域,代码运行良好。然而,当我试图检查通过用户名指定的另一个域时,我会收到一个"无法联系服务器"的错误。
我还尝试使用不同的ContextOptions
,如ContextOptions.SimpleBind
或ContextOptions.Negotiate
,但似乎总是得到相同的结果。
我需要实现这一点,因为应用程序正通过单域或多域环境交付给各种客户。在"远程"域的情况下,我还应该指定其他内容吗?代码需要灵活,因为它将部署在各种环境中。
感谢
EDIT:我必须指出,我更喜欢使用DirectoryServices.AccountManagement
和PrincipalContext
进行编辑,以便利用它提供的其他功能。
此外,我必须提到,对于我的测试,我的Dev机器在10.0.0.*网络上,我测试的第二个域在10.0.1.*网络上。我有一个路由和所有的,我可以使用ldap客户端成功连接,所以问题是为什么我不能通过asp.net应用程序连接到域。
我已经想出了这个问题的解决方案。
为了支持多个域,无论是在信任关系中,还是在隔离网络中,首先我在web.config中添加了一个NameValueCollection,以列出域及其域控制器。
<domains>
<add key="domain1" value="10.0.0.1"/>
<add key="domain2" value="10.0.1.11"/>
</domains>
(在这个问题中添加配置的更多信息)
然后下一步是按照我在问题中提到的方式从用户的凭据中读取域。获得域后,我尝试从配置值中查找相应的域控制器,以便获得正确的LDAP连接字符串。所以我的方法是:
private string GetLDAPConnection(string a_Domain, string a_Username, string a_Password)
{
// Get the domain controller server for the specified domain
NameValueCollection domains = (NameValueCollection)ConfigurationManager.GetSection("domains");
string domainController = domains[a_Domain.ToLower()];
string ldapConn = string.Format("LDAP://{0}/rootDSE", domainController);
DirectoryEntry root = new DirectoryEntry(ldapConn, a_Username, a_Password);
string serverName = root.Properties["defaultNamingContext"].Value.ToString();
return string.Format("LDAP://{0}/{1}", domainController, serverName);
}
一旦我得到正确的连接字符串,我就会进行一个新的调用,以便通过寻址正确的LDAP 来验证用户
...
string ldapConn = GetLDAPConnection(domain, username, a_Password);
DirectoryEntry entry = new DirectoryEntry(ldapConn, username, a_Password);
try
{
try
{
object obj = entry.NativeObject;
}
catch(DirectoryServicesCOMException comExc)
{
LogException(comExc);
return false;
}
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = string.Format("(SAMAccountName={0})", username);
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
从这一点开始,我还可以执行我想要的所有其他查询,例如用户的组成员资格等。
由于对远程域的调用需要绑定到用户;呼叫";用户凭据。通过这种方式,用户可以获得身份验证,并且调用绑定到特定用户。此外,我指定一个";默认";域,用于用户在不指定域的情况下提供凭据的情况。
然而,我并没有按照自己的意愿使用PrincipalContext来实现这一点,但从好的方面来看,该解决方案也适用于较旧的.NET 2.0应用程序。
我不确定这是否是解决这个问题的最佳方案,但它似乎在我们迄今为止进行的测试中起作用。
我不知道为什么我被否决了,但我认为这可能是错误的,您代码所在的服务器/域与您试图联系的域之间的信任级别可能无法建立。我无法向你解释为什么会发生这种情况。
[EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
你可以尝试在你的功能上添加这个,看看它是否能帮助你完成,但除此之外,我不明白为什么在WinNT域上搜索所有可能的用户是错误的。希望这能帮助