如何在有大量用户的 Ldap 服务器上进行分页搜索?

How to do a paged search on an Ldap server with lots of users?(如何在有大量用户的 Ldap 服务器上进行分页搜索?)
本文介绍了如何在有大量用户的 Ldap 服务器上进行分页搜索?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要创建一个使用 .NET Core 在 linux 上工作的 LDAP 客户端.我搜索了互联网,唯一支持 .Net 标准的库是 Novell.Directory.Ldap (开源,iei - https://github.com/dsbenghe/Novell.Directory.Ldap.NETStandard).目录服务库在 .Net Core for Linux 中不支持,仅在 Windows 上支持.

我查看了文档并成功创建了一个基本的 Ldap 客户端应用程序.

现在的问题:我需要同步很多用户(10.000、200.000 个用户),默认情况下我的 ldap 服务器的最大页面大小为 1000(我不想更改它)).我使用 VirtualListControl 来创建页面,它适用于 10k 用户.

对于 200k 用户,它会因错误 53 而崩溃 - 不愿意对 LdapSortControl 响应执行.Novell 库需要一个 LdapSortControl 才能执行分页操作(用于索引),我认为我的 ldap 无法对 200k 进行排序.我使用的代码:

 int startIndex = 1;int contentCount = 0;int afterIndex = 10;整数计数 = 0;做{LdapVirtualListControl ctrl = new LdapVirtualListControl(startIndex, 0, afterIndex, contentCount);LdapSortKey[] 键 = 新 LdapSortKey[1];键[0] = new LdapSortKey("sn");LdapSortControl sort = new LdapSortControl(keys, true);LdapSearchConstraints 约束 = _ldapConnection.SearchConstraints;约束.setControls(new LdapControl[] { ctrl, sort});_ldapConnection.Constraints = 约束;LdapSearchResults lsc = _ldapConnection.Search(searchBase, searchScope, searchFilter, attributes, typesOnly, cons);而 (lsc.HasMore()){尝试{LdapEntry nextEntry = lsc.Next();Console.WriteLine(nextEntry.DN);}捕捉(LdapException e){Console.WriteLine($"错误:{e.LdapErrorMessage}");//抛出异常,进入下一个入口继续;}}LdapControl[] 控制 = lsc.ResponseControls;如果(控制 == 空){Console.Out.WriteLine("没有控件返回");}别的{foreach(控件中的 LdapControl 控件){if (control.ID == "2.16.840.1.113730.3.4.10"){LdapVirtualListResponse response = new LdapVirtualListResponse(control.ID, control.Critical, control.getValue());startIndex += afterIndex + 1;内容计数=响应.内容计数;计数 += 后索引;}}}Console.WriteLine(i);} while (count <= contentCount);

文档很小,没有足够的信息,我不知道如何使用 Novell 库以更好的方式进行分页.这里有没有人使用 Novell Ldap 库并且有任何分页经验并且也可以帮助我?我分散了

谢谢

解决方案

要使用 Novell.Directory.Ldap 进行分页查询,您必须使用 LdapVirtualListControl 作为请求"控件.

LdapVirtualListControl 尊重 Ldap 排序请求控件的参数:VLV(虚拟列表视图)是:

before:after:index:content_count

其中before"是您希望在索引之前返回的项目数,after"是您希望在 AFTER 之后返回的项目数索引和content_count"是服务器中项目的预期总数.如果你不知道,你必须使用 0 作为值.

如果要通过ldapsearch"cli 返回前 5 个元素,则必须使用:'0:4:1:0' 和 '0:4:5:0' 用于后面的五个元素.

LdapVirtualListControl 拥有一个具有相同参数但顺序不同的构造函数:

LdapVirtualListControl(int startIndex, int beforeCount, int afterCount, int contentCount)

就个人而言,我使用这个函数来正确设置参数:

public static LdapSearchConstraints AddPagination(这个 LdapSearchConstraints 约束, int page,整数页大小){int startIndex = (page - 1) * pageSize;开始索引++;int beforeCount = 0;int afterCount = pageSize - 1;int contentCount = 0;//0 表示我不知道总数var lvlc = new LdapVirtualListControl(startIndex, beforeCount, afterCount, contentCount);约束.setControls(lvlc);返回约束;}

之后,需要注意另一个问题:如果您要求一组数据,这些数据位于数据集的末尾之后,您将收到数据集的第一个项目.

解释:

ldap 中存在的数据示例:
|1 |2 |3 |4 |
如果我们要求集合
________|3 |4 |5 |<- 5 不存在
Ldap 返回:
________|3 |4 |1 |<- 从头开始​​

为了解决这个问题,我在返回之前删除了超出的元素:

var lastIndex = (page * pageSize);if (lastIndex > result.Total){var itemsToReturn = (int) (result.Total - (lastIndex - pageSize));if (itemsToReturn <1){项目=新列表<LdapQueryItem>();}别的{items = items.Take(itemsToReturn).ToList();}}

最后是获取总数的函数(在 searchResults.HasMore() 方法之后执行)

受保护的整数?GetTotal(LdapSearchResults 搜索结果){if (searchResult == null) {抛出新的 ArgumentNullException(nameof(searchResult));}if (searchResult.ResponseControls != null && searchResult.ResponseControls.Any()){foreach(searchResult.ResponseControls 中的 LdapControl 控件){if (control.ID == "2.16.840.1.113730.3.4.10")//响应控件的id{LdapVirtualListResponse 响应 =新的 LdapVirtualListResponse(control.ID, control.Critical, control.getValue());返回响应.内容计数;}}}返回空值;}

您可以获得有关本书的更多见解和信息:了解和部署 LDAP 目录服务p>

I need to create a LDAP client that works on linux using .NET Core. I searched trought the internet and the only library that support .Net Standard is Novell.Directory.Ldap (open source, iei - https://github.com/dsbenghe/Novell.Directory.Ldap.NETStandard). Directory Service library does not have support in .Net Core for Linux, only on Windows.

I looked to the documentation and succeded to create a basic Ldap client application.

Now the problem: I need to synchronize a lot of users (10.000, 200.000 users) and by default my ldap server has a maximum size page 1000 (and I don't want to change it). I used a VirtualListControl in order to create pages and it works ok for 10k users.

For 200k user it crashes with error 53 - unwilling to perform on the LdapSortControl response. The Novell library need a LdapSortControl in order to perform paging operation (for index) and I think that my ldap is not able to sort 200k. The code that I used:

        int startIndex = 1;
        int contentCount = 0;
        int afterIndex = 10;
        int count = 0;
        do
        {
            LdapVirtualListControl ctrl = new LdapVirtualListControl(startIndex, 0, afterIndex, contentCount);
            LdapSortKey[] keys = new LdapSortKey[1];
            keys[0] = new LdapSortKey("sn");
            LdapSortControl sort = new LdapSortControl(keys, true);

            LdapSearchConstraints constraints = _ldapConnection.SearchConstraints;
            constraints.setControls(new LdapControl[] { ctrl, sort});

            _ldapConnection.Constraints = constraints;
            LdapSearchResults lsc = _ldapConnection.Search(searchBase, searchScope, searchFilter, attributes, typesOnly, cons);
            while (lsc.HasMore())
            {
                try
                {
                    LdapEntry nextEntry = lsc.Next();
                    Console.WriteLine( nextEntry.DN);
                }
                catch (LdapException e)
                {
                    Console.WriteLine($"Error: {e.LdapErrorMessage}");
                    //Exception is thrown, go for next entry
                    continue;
                }

            }

            LdapControl[] controls = lsc.ResponseControls;
            if (controls == null)
            {
                Console.Out.WriteLine("No controls returned");
            }
            else
            {
                foreach (LdapControl control in controls)
                {
                    if (control.ID == "2.16.840.1.113730.3.4.10")
                    {
                        LdapVirtualListResponse response = new LdapVirtualListResponse(control.ID, control.Critical, control.getValue());
                        startIndex += afterIndex + 1;
                        contentCount = response.ContentCount;
                        count += afterIndex;
                    }
                }
            }
            Console.WriteLine(i);

        } while (count <= contentCount);

The documentation is small and does not have enough information and I have no idea how to use Novell library for paging in a better way. Is anybody here that use Novell Ldap library and have any experience with paging and also can help me? I'm disperate

Thank you

解决方案

To make a paged query with Novell.Directory.Ldap you have to use LdapVirtualListControl as "Request" Control.

LdapVirtualListControl respects the arguments of the Ldap Sorting Request Control: VLV (Virtual List View) that are:

before:after:index:content_count

where "before" is the number of items that you want to be returned BEFORE the index, "after" the number of items that you want to be returned AFTER the index and "content_count" is the expected total count of items in the server. In case you do not know it, you have to use 0 as value.

If you want to return the first 5 elements via "ldapsearch" cli, you have to use: '0:4:1:0' and '0:4:5:0' for the subsequent five ones.

The LdapVirtualListControl owns a constructor with the same arguments but with a different order:

LdapVirtualListControl(int startIndex, int beforeCount, int afterCount, int contentCount)

Personally, I use this function to set the arguments correctly:

public static LdapSearchConstraints AddPagination(this LdapSearchConstraints constraints, int page,
            int pageSize)
{
    int startIndex = (page - 1) * pageSize;
    startIndex++;
    int beforeCount = 0;
    int afterCount = pageSize - 1;
    int contentCount = 0; //0 means that i don't know the total count

    var lvlc = new LdapVirtualListControl(startIndex, beforeCount, afterCount, contentCount);
    constraints.setControls(lvlc);
    return constraints;
}

After that, another issue needs your attention: if you ask for a set of data, which are positioned after the end of the data-set, you will receive back the first items of the dataset.

Explanation:

Example of data present in ldap:
| 1 | 2 | 3 | 4 |
if we ask for the set
________| 3 | 4 | 5 | <- 5 does not exists
Ldap returns:
________| 3 | 4 | 1 | <- it starts over from the beginning

To fix this issue, I remove the exceeded elements before return:

var lastIndex = (page * pageSize);
if (lastIndex > result.Total)
{
    var itemsToReturn = (int) (result.Total - (lastIndex - pageSize));
    if (itemsToReturn < 1)
    {
        items = new List<LdapQueryItem>();
    }
    else
    {
        items = items.Take(itemsToReturn).ToList();
    }
}   

Finally, the function to get the totals (to execute AFTER the searchResults.HasMore() method)

protected int? GetTotal(LdapSearchResults searchResult)
{
    if (searchResult == null) {
       throw new ArgumentNullException(nameof(searchResult));
    }
    if (searchResult.ResponseControls != null && searchResult.ResponseControls.Any())
    {
        foreach (LdapControl control in searchResult.ResponseControls)
        {
            if (control.ID == "2.16.840.1.113730.3.4.10") // the id of the response control
            {
                LdapVirtualListResponse response =
                    new LdapVirtualListResponse(control.ID, control.Critical, control.getValue());
                return response.ContentCount;
            }
        }
    }

    return null;
}

You can get further insights and info on this book: Understanding and Deploying LDAP Directory Services

这篇关于如何在有大量用户的 Ldap 服务器上进行分页搜索?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)