2

在我工作的地方,我们有两种身份验证模式:

CAS 是主要方法,但在流量高峰期通常不可靠,因此当我们注意到 CAS 已关闭时,我们一直使用 LDAP 作为备用模式。以前,我们使用 PHP 进行 LDAP 回退并获得了合理的性能。除了预期的网络延迟时间外,登录期间没有明显的延迟。使用 LDAP 完成登录大概需要 250-500 毫秒。

现在,我们正在制作一个新系统,并选择了 ASP.NET MVC4 作为平台而不是 PHP,我的任务是尝试让这个后备方案再次工作。我已经拉了大约 6 个小时的头发,现在一遍又一遍地尝试不同的东西,得到相同的结果(也许我疯了)。我终于设法连接到 LDAP,对用户进行身份验证,并从 LDAP 获取他们的属性。但是,无论我尝试什么方法,查询始终需要 4.5 秒才能完成。

看到 PHP 版本能够以 1/8 的时间完成几乎相同的事情,这让我感到非常惊讶,而且 .NET 框架似乎对 LDAP/ActiveDirectory 具有出色的支持。我在做一些非常可怕的错误吗?

这是我现在的功能的内容(这是最新的迭代,它设法在一个 4.5 秒的查询中完成所有操作):

public Models.CASAttributes Authenticate(string username, string pwd)
{
    string uid = string.Format("uid={0},ou=People,o=byu.edu", username);

    LdapDirectoryIdentifier identifier = new LdapDirectoryIdentifier("ldap.byu.edu", 636, false, false);

    try
    {
        using (LdapConnection connection = new LdapConnection(identifier))
        {
            connection.Credential = new NetworkCredential(uid, pwd);
            connection.AuthType = AuthType.Basic;
            connection.SessionOptions.SecureSocketLayer = true;
            connection.SessionOptions.ProtocolVersion = 3;

            string filter = "(uid=" + username + ")";
            SearchRequest request = new SearchRequest("ou=People,o=byu.edu", filter, SearchScope.Subtree);
            Stopwatch sw = Stopwatch.StartNew();
            SearchResponse response = connection.SendRequest(request) as SearchResponse;
            sw.Stop();
            Debug.WriteLine(sw.ElapsedMilliseconds);
            foreach (SearchResultEntry entry in response.Entries)
            {
                Debug.WriteLine(entry.DistinguishedName);
                foreach (System.Collections.DictionaryEntry attribute in entry.Attributes)
                {
                    Debug.WriteLine(attribute.Key + " " + attribute.Value.GetType().ToString());
                }
                Debug.WriteLine("");
            }
        }
    }
    catch
    {
        Debugger.Break();
    }

    Debugger.Break();
    return null; //debug
}

其 PHP 版本遵循以下顺序:

  1. 匿名绑定,使用 basedn 和 cn 查找用户信息
  2. 使用用户的用户名和密码再次绑定,看看是否真实

它执行两次绑定(连接?)的时间是 .NET 版本执行一次的时间的 1/8!正是这种事情让我觉得我错过了一些东西。

我尝试了基于以下站点的方法:

编辑:

使用wireshark,我看到了以下请求:

  1. bindRequest 沿我的 uid 传递(增量 0.7 毫秒)
  2. bindResponse 成功(增量 2 毫秒)
  3. searchRequest "ou=People,o=byu.edu" wholdSubtree (delta 0.2ms)
  4. searchResEntry "uid=我的 uid ,ou=People,o=byu.edu" | searchResDone 成功 1 个结果(增量 10.8 毫秒)
  5. unbindRequest(增量 55.7 毫秒)

显然,开销来自 .NET 而不是请求。这些以任何方式、形状或形式加起来都不超过 4.5 秒。

4

2 回答 2

3

ldap.byu.edu肯定看起来像一个完全限定的 DNS 主机名。您应该将 LdapDirectoryIdentifier 构造函数更改为new LdapDirectoryIdentifier("ldap.byu.edu", 636, true, false).

于 2013-08-15T01:14:24.273 回答
2

我认为你肯定是在正确的轨道上使用System.DirectoryServices这个,所以你可能只需要稍微调整你的搜索请求。

你只是想在这里得到一个结果,对吗?相应地设置您的尺寸:

request.SizeLimit = 1;

这是一个棘手的问题,但还要确保您也抑制了引用绑定。您需要在调用之前进行设置connection.SendRequest(request)

//Setting the DomainScope will suppress referral binds from occurring during the search
SearchOptionsControl SuppressReferrals = new SearchOptionsControl(SearchOption.DomainScope);
request.Controls.Add(SuppressReferrals);
于 2013-08-13T20:13:30.893 回答