首页 > 技术文章 > LDAP操作的两种方案

rangeon 2017-07-07 15:34 原文

最近由于项目需要研究了一下LDAP相关知识,感觉对没接触过的人来说还是有点坑的,所以记录下来给大家分享。

由于是第一次接触,就在网上搜了一些相关的文章,照着示例代码测试,却怎么也连不上LDAP服务器,最后折腾的能连上服务器了,又不能检索用户。

折腾过程中遇到的主要错误就是:

  • There is no such object on the server.

  • The username or password is incorrect.

  • The server could not be contacted.

在经历了N小时的煎熬之后,终于找到了第一种解决方案,其实就是参考网上的示例代码,但是示例代码的AuthenticationTypes是None,测试连接的时候总是不能正常连接,LDAP地址只能写host,后面不能跟DN,否则就连不上服务器,而且这种方法连接上服务器也不能检索用户。后来改为AuthenticationTypes.FastBind之后才能正常工作了。

 1     //----------------------------------------------------------------------------------------------
 2     // DirectoryEntry 方案, 需要引用 System.DirectoryServices
 3     //----------------------------------------------------------------------------------------------
 4     var ldapPath = "LDAP://" + host + "/" + baseDN; // LDAP必须要大写,好像是.NET的特色
 5     DirectoryEntry de = new DirectoryEntry(ldapPath, adminName, adminPass, AuthenticationTypes.FastBind);
 6     DirectorySearcher searcher = new DirectorySearcher(de);
 7     searcher.Filter = "(uid=" + testUser + ")";
 8     searcher.SearchScope = SearchScope.Subtree;
 9     searcher.PropertiesToLoad.Add("uid");
10     searcher.PropertiesToLoad.Add("cn");
11 
12     var result = searcher.FindOne();
13     
14     // 输出几个查询的属性值
15     foreach (string n in result.Properties.PropertyNames)
16     {
17         Console.WriteLine("{0}: {1}", n, result.Properties[n][0].ToString());
18     }
19 
20     try
21     {
22         int pos = result.Path.LastIndexOf('/');
23         string uid = result.Path.Remove(0, pos + 1);
24         
25         // 二次连接,使用需要认证的用户密码尝试连接
26         DirectoryEntry deUser = new DirectoryEntry(ldapPath, uid, testPass, AuthenticationTypes.FastBind);
27         var connected = deUser.NativeObject;
28         
29         Console.WriteLine("### 认证成功!");
30     }
31     catch
32     {
33         Console.WriteLine("认证失败~~~");
34     }

 

另外一种方案是我同事找到的,和我上面一种方案几乎在同一时间找到,比较坑,是使用.NET官方类库中的LdapConnection,我一直认为LDAP这么常见的东西一定有官方的解决方案,奈何搜遍了国内外的中文、E文网站,“LDAP C#”、“LDAP .NET”关键字都搜了,就是没有任何人提到关于这个类的片言只字,真无语!难道这玩意就这么冷门吗?难道大家都在用DirectoryEntry吗?不可思议。

 1     //------------------------------------------------------------------------------------------
 2     // LdapConnection 方案, 需要引用 System.DirectoryServices.Protocols
 3     //------------------------------------------------------------------------------------------
 4     var identifier = new LdapDirectoryIdentifier(host);
 5     var conn = new LdapConnection(identifier, new NetworkCredential
 6     {
 7         UserName = adminName,
 8         Password = adminPass
 9     });
10     conn.AuthType = AuthType.Basic;
11     conn.Bind();
12 
13     var request = new SearchRequest(baseDN, "(uid=" + testUser + ")", SearchScope.Subtree, "otherPassword");
14     SearchResponse response = conn.SendRequest(request) as SearchResponse;
15     if (response.Entries != null && response.Entries.Count > 0)
16     {
17         try
18         {
19             var connUser = new LdapConnection(identifier, new NetworkCredential
20             {
21                 UserName = response.Entries[0].DistinguishedName,
22                 Password = testPass
23             });
24             connUser.AuthType = AuthType.Basic;
25             connUser.Bind();
26 
27             Console.WriteLine("### 认证成功!");
28         }
29         catch
30         {
31             Console.WriteLine("认证失败~~~ error password");
32         }
33     }
34     else
35     {
36         Console.WriteLine("认证失败~~~ no user");
37     }

 

 

测试代码中用到的一些变量声明:

1     var host = "xxx.xxx.xxx.xxx:389";
2     var baseDN = "dc=xxx,dc=xxx,dc=com";
3     var adminName = "uid=管理账号,ou=管理组," + baseDN;
4     var adminPass = "管理密码";
5     var testUser = "测试认证用户账号";
6     var testPass = "测试认证用户密码";

 

推荐阅读