`
kobe学java
  • 浏览: 257425 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

Sun Directory Server/LDAP学习笔记(二)——API说明及代码样例

 
阅读更多

相关文章:Sun Directory Server/LDAP学习笔记(一)——LDAP协议简述 

Java6.0 API for LDAP概述 

从JDK5.0开始,对LDAP协议的数据访问操作就被集成在javax的扩展API包中,并随同JDK一并发布,这一章节,我们主要介绍API包中的类信息。 
javax.naming.directory 包的结构 
 

常用API解析 

javax.naming.directory.InitialDirContext,初始化目录服务上下文类 
该类是LDAP数据内容的操作工具类,通过该类可以执行绑定LDAP服务器、新增LDAP条目、获取条目实例、修改条目属性、删除条目和根据条件搜索条目等操作。常用方法说明如下: 

初始化LDAP 目录服务上下文(相当于使用JDBC打开一个数据库链接)
  • InitialDirContext(Hashtable<?,?> environment)

绑定/创建LDAP条目对象(相当于新增一个LDAP条目数据bind(Name
  • name, Object obj, Attributes attrs)
  • bind(String name, Object obj, Attributes attrs)
  • createSubcontext(Name name, Attributes attrs)
  • createSubcontext(String name, Attributes attrs)

获取条目实例(属性集) 
  • getAttributes(Name name)
  • getAttributes(Name name, String[] attrIds)
  • getAttributes(String name)
  • getAttributes(String name, String[] attrIds)

修改条目属性 
  • modifyAttributes(Name name, int mod_op, Attributes attrs)
  • modifyAttributes(Name name, ModificationItem[] mods)
  • modifyAttributes(String name, int mod_op, Attributes attrs)
  • modifyAttributes(String name, ModificationItem[] mods)

删除条目 
  • destroySubcontext(Name name)
  • destroySubcontext(String name)

根据属性集搜索条目 
  • search(Name name, Attributes matchingAttributes)
  • search(Name name, Attributes matchingAttributes, String[] attributesToReturn)
  • search(String name, Attributes matchingAttributes)
  • search(String name, Attributes matchingAttributes, String[] attributesToReturn)

根据过滤器搜索条目 
  • search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons)
  • search(Name name, String filter, SearchControls cons)
  • search(String name, String filterExpr, Object[] filterArgs, SearchControls cons)
  • search(String name, String filter, SearchControls cons)


javax.naming.directory.BasicAttribute,LDAP基本属性对象 
该类用来表示LDAP条目中的单个属性对象。在目录服务中,每个属性名称是可以对应多个的属性值的。 

构建属性对象 
  • BasicAttribute(String id)
  • BasicAttribute(String id, boolean ordered)
  • BasicAttribute(String id, Object value)
  • BasicAttribute(String id, Object value, boolean ordered)

添加属性值 
  • add(int ix, Object attrVal),添加属性值到多值属性的指定位置
  • add(Object attrVal) , 追加属性值到多值属性尾部

判断属性值是否包含 
  • contains(Object attrVal) , 多值属性中有一个值是匹配的,返回true

获取属性值 
  • get(),取得属性值中的一个
  • get(int ix),从多值属性中的指定位置取值

获取属性ID 
  • getID(),属性的ID就是属性名

删除属性值 
  • remove(int ix),删除指定位置的属性值
  • remove(Object attrval),删除指定的属性值


javax.naming.directory.BasicAttributes,LDAP实体的属性集 
该类表示一个LDAP条目绑定的属性集合,在绝大多数情况下,一个LDAP条目存在多个属性。 

构造属性集 
  • BasicAttributes()
  • BasicAttributes(boolean ignoreCase),属性ID是否大小写敏感,建议不要使用敏感
  • BasicAttributes(String attrID, Object val)
  • BasicAttributes(String attrID, Object val, boolean ignoreCase)

获取属性集中的单个属性对象 
  • get(String attrID)

获取全部属性的枚举 
  • getAll()

获取全部属性的ID枚举 
  • getIDs()

添加新属性 
  • put(Attribute attr)
  • put(String attrID, Object val)
 
移除指定属性 
  • remove(String attrID)


javax.naming.directory.SearchControls , LDAP目录服务搜索控制对象 
该类负责控制LDAP搜索行为的范围、设定返回结果数上限,搜索耗时上限,指定结果所包括的属性集等。 

设定搜索行为的范围 
  • setSearchScope(int scope)
 
设定返回结果数上限 
  • setCountLimit(long limit)

设定搜索耗时上限 
  • setTimeLimit(int ms) , 以毫秒为单位

指定结果所包括的属性集 
  • setReturningAttributes(String[] attrs)


javax.naming.directory.SearchResult , 表示.search() 方法的返回结果集中的一项。 
SearchResult类是对LDAP条目属性集的封装。在search()操作中可能返回完整的条目属性,也可能是条目属性的一部分。 

获取SearchResult封装的条目属性 
  • getAttributes()


以上只列举了LDAP操作API的常用部分,更多更详细的描述,请参考 Sun Java6.0 API DOC。 

LDAP操作代码样例 
在这个章节中,我们将结合LDAP操作的代码实例了解API使用。 

初始化LDAP 目录服务上下文 
该例子中,我们使用uid=linly,ou=People,dc=jsoso,dc=net这个账号,链接位于本机8389端口的LDAP服务器(ldap://localhost:8389),认证方式采用simple类型,即用户名/密码方式。 
Java代码   收藏代码
  1. private static void initialContext() throws NamingException{  
  2.     if(singleton == null){  
  3.         singleton = new LDAPConnection();  
  4.         /* 
  5.          * 在实际编码中,这些环境变量应尽可能通过配置文件读取 
  6.          */  
  7.         //LDAP服务地址  
  8.         singleton.sLDAP_URL = "ldap://localhost:8389";   
  9.         //管理员账号  
  10.         singleton.sMANAGER_DN = "uid=linly,ou=People,dc=jsoso,dc=net";  
  11.         //管理员密码  
  12.         singleton.sMANAGER_PASSWORD = "coffee";  
  13.         //认证类型  
  14.         singleton.sAUTH_TYPE = "simple";  
  15.         //JNDI Context工厂类  
  16.         singleton.sCONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";   
  17.           
  18.         singleton.envProps.setProperty(Context.INITIAL_CONTEXT_FACTORY, singleton.sCONTEXT_FACTORY);  
  19.         singleton.envProps.setProperty(Context.PROVIDER_URL, singleton.sLDAP_URL);  
  20.         singleton.envProps.setProperty(Context.SECURITY_AUTHENTICATION, singleton.sAUTH_TYPE);  
  21.         singleton.envProps.setProperty(Context.SECURITY_PRINCIPAL, singleton.sMANAGER_DN);  
  22.         singleton.envProps.setProperty(Context.SECURITY_CREDENTIALS, singleton.sMANAGER_PASSWORD);  
  23.         /* 
  24.          * 绑定ldap服务器 
  25.          */  
  26.         singleton.dirCtx = new InitialDirContext(singleton.envProps);  
  27.     }  
  28. }  

通过一个Hashtable或者Properties对象为LDAP的Context设置参数,而后初始化InitialDirContext,即可绑定LDAP服务。这相当于JDBC中获取数据库的Connection对象。 

绑定/创建LDAP条目对象 
用户可以使用bind方法创建新的LDAP条目,下面的代码创建一个DN:"ou=Employee , dc=jsoso ,dc=net"的OrganizationUnit类LDAP条目如下: 
Java代码   收藏代码
  1. public boolean createOrganizationUnit(){  
  2.     String ldapGroupDN = "ou=Employee , dc=jsoso ,dc=net";  
  3.     try {  
  4.         /* 
  5.          * 查找是否已经存在指定的OU条目 
  6.          * 如果存在,则打印OU条目的属性信息 
  7.          * 如果不存在,则程序会抛出NamingException异常,进入异常处理 
  8.          */  
  9.         Attributes attrs = dirContext.getAttributes(ldapGroupDN);  
  10.         System.out.println("Find the group , attributes list :");  
  11.         NamingEnumeration<String>  nEnum = attrs.getIDs();              
  12.         for( ; nEnum.hasMore() ; ){  
  13.             String attrID = nEnum.next();  
  14.             Attribute attr = (Attribute)attrs.get(attrID);  
  15.             System.out.println(attr.toString());  
  16.         }             
  17.         return false;  
  18.     } catch (NamingException e) {  
  19.         /* 
  20.          * 没有找到对应的Group条目,新增Group条目 
  21.          */  
  22.         //创建objectclass属性  
  23.         Attribute objclass = new BasicAttribute("objectclass");  
  24.         objclass.add("top");  
  25.         objclass.add("organizationalunit");   
  26.         //创建cn属性  
  27.         Attribute cn = new BasicAttribute("ou""Employee");   
  28.         //创建Attributes,并添加objectclass和cn属性  
  29.         Attributes attrs = new BasicAttributes();   
  30.         attrs.put(objclass);   
  31.         attrs.put(cn);   
  32.         //将属性绑定到新的条目上,创建该条目  
  33.         try {  
  34.             dirContext.bind(ldapGroupDN, null, attrs);  
  35.             System.out.println("Group created successful");  
  36.             return true;  
  37.         } catch (NamingException e1) {  
  38.             e1.printStackTrace();  
  39.         }             
  40.     }  
  41.     return false;  
  42. }  

或者使用createSubcontext方法创建亦可,以下例子我们新增一个inetorgperson类的LDAP条目: 
Java代码   收藏代码
  1. /** 
  2.  * 创建LDAP用户条目 
  3.  * @param user  
  4.  * @return 
  5.  */  
  6. public boolean createUser(LDAPUser user){  
  7.     if(user == null){  
  8.         return false;  
  9.     }  
  10.       
  11.     if(user.getUserID() == null || user.getUserID().length() == 0   
  12.             || user.getFirstName() == null || user.getFirstName().length() == 0  
  13.             || user.getLastName() == null || user.getLastName().length() == 0  
  14.             || user.getCommomName() == null || user.getCommomName().length() == 0){  
  15.         return false;  
  16.     }  
  17.   
  18.     //判断用户条目是否已经存在  
  19.     if(isUserexist(user.getDistinguishedName())){  
  20.         return true;  
  21.     }  
  22.   
  23.     /* 
  24.      * 新建条目属性集 
  25.      */  
  26.     Attributes attrs = new BasicAttributes();   
  27.     setBasicAttribute(attrs , "objectclass" , "top,person,organizationalPerson,inetorgperson");  
  28.     setBasicAttribute(attrs , "cn" , user.getCommomName());  
  29.     setBasicAttribute(attrs , "givenname" , user.getFirstName());  
  30.     setBasicAttribute(attrs , "sn" , user.getLastName());  
  31.     setBasicAttribute(attrs , "uid" , user.getUserID());  
  32.     setBasicAttribute(attrs , "userpassword" , user.getPassword());  
  33.   
  34.     //添加用户条目节点   
  35.     try {  
  36.         dirContext.createSubcontext(user.getDistinguishedName(), attrs);  
  37.         System.out.println("Add User(" + user.getDistinguishedName() + ") ok.");   
  38.         return true;  
  39.     } catch (NamingException e) {  
  40.         e.printStackTrace();  
  41.     }   
  42.     return false;  
  43. }  


获取条目属性 
下面一段代码获取entryDN参数指定条目中的属性集合,并打印到控制台 
Java代码   收藏代码
  1. /** 
  2.  * 获取一个指定的LDAP Entry 
  3.  * @param entryDN 
  4.  */  
  5. public void find(String entryDN){  
  6.     try {   
  7.         Attributes attrs = dirContext.getAttributes(entryDN);   
  8.         if (attrs != null) {  
  9.             NamingEnumeration<String>  nEnum = attrs.getIDs();  
  10.             for( ; nEnum.hasMore() ; ){  
  11.                 String attrID = nEnum.next();  
  12.                 Attribute attr = (Attribute)attrs.get(attrID);  
  13.                 System.out.println(attr.toString());  
  14.             }  
  15.             System.out.println();  
  16.         }else{   
  17.             System.out.println("No found binding.");  
  18.         }   
  19.     }catch(NamingException ne) {   
  20.         ne.printStackTrace();  
  21.     }   
  22. }  


修改条目属性 
修改DN=user.getDistinguishedName()的条目中的cn、givenname、sn和userpassword四个属性值。 
(注:参数DirContext.REPLACE_ATTRIBUTE有另外两个常量:DirContext.ADD_ATTRIBUTE;DirContext.REMOVE_ATTRIBUTE,分别表示新增属性和删除属性。) 
Java代码   收藏代码
  1. /** 
  2.  * 修改用户信息 
  3.  * @param user 
  4.  * @return 
  5.  * @throws Exception 
  6.  */   
  7. public boolean modifyUser(LDAPUser user) throws Exception {   
  8.     //用户对象为空   
  9.     if (user == null) {   
  10.         throw new Exception("No user information!n");   
  11.     }  
  12.   
  13.     //检查uid   
  14.     String userDN = user.getDistinguishedName();   
  15.     if (userDN == null && userDN.length() == 0) {   
  16.         throw new NamingException("No userDN you specify!n");   
  17.     }   
  18.   
  19.     //判断用户条目是否已经存在  
  20.     if(!isUserexist(userDN)){  
  21.         return false;  
  22.     }  
  23.       
  24.     //设置属性   
  25.     Attributes attrs = new BasicAttributes();   
  26.     setBasicAttribute(attrs, "cn", user.getCommomName());   
  27.     setBasicAttribute(attrs, "givenname", user.getFirstName());   
  28.     setBasicAttribute(attrs, "sn", user.getLastName());   
  29.     setBasicAttribute(attrs, "userpassword", user.getPassword());     
  30.     //修改属性   
  31.     try{  
  32.         dirContext.modifyAttributes(user.getDistinguishedName(),DirContext.REPLACE_ATTRIBUTE, attrs);   
  33.         System.out.println("User(" + user.getDistinguishedName() + ") information modified.n");  
  34.         return true;  
  35.     }catch(NamingException ne){  
  36.         ne.printStackTrace();  
  37.     }  
  38.     return false;  
  39. }  


删除条目 
删除DN= userDN条目 
Java代码   收藏代码
  1. /** 
  2.  * 删除用户 
  3.  * @param userDN 
  4.  * @return 
  5.  */  
  6. public boolean deleteUser(String userDN) {   
  7.     if(!isUserexist(userDN)) {   
  8.         return true;  
  9.     }   
  10.     try {  
  11.         dirContext.destroySubcontext(userDN);  
  12.         System.out.println("User( " + userDN + ") deleted.n");   
  13.         return true;  
  14.     } catch (NamingException e) {  
  15.         e.printStackTrace();  
  16.     }   
  17.     return false;         
  18. }  


根据属性集搜索条目 
根据属性集matchingAttributes中的匹配值,在上下文DN= "ou=People,dc=jsoso ,dc=net"中搜索它的所有子树中的匹配条目。 
(注:SearchControls的SCOPE参数详见SearchControls SCOPE补充说明)
Java代码   收藏代码
  1.          /** 
  2.  * 通过属性搜索LDAP范例  
  3.  * @return 
  4.  */  
  5. public void searchByAttribute(Attributes matchingAttributes){  
  6.      String baseDN = "ou=People,dc=jsoso ,dc=net";  
  7.      SearchControls cons = new SearchControls();  
  8.      cons.setSearchScope(SearchControls.SUBTREE_SCOPE);  
  9.      try {  
  10.         Name baseName = new LdapName(baseDN);  
  11.         NamingEnumeration<SearchResult> ne = dirContext.search(baseName, matchingAttributes);  
  12.         SearchResult entry = null;  
  13.         for(;ne.hasMore();){  
  14.             entry = ne.next();  
  15.             showEntry(entry);  
  16.         }                     
  17.     } catch (NamingException e) {  
  18.         e.printStackTrace();  
  19.     }  
  20. }  


根据过滤器搜索条目 
根据过滤器条件,在上下文DN = "ou=People,dc=jsoso ,dc=net"中,搜索它的所有子树中的匹配条目。 
(注:过滤器filter的相关语法详见LDAP filter语法补充说明) 
Java代码   收藏代码
  1. /** 
  2.  * 通过过滤器搜索LDAP范例  
  3.  * @return 
  4.  */  
  5. public void searchByFilter(String filter){  
  6.      String baseDN = "ou=People,dc=jsoso ,dc=net";         
  7.      SearchControls cons = new SearchControls();  
  8.      cons.setSearchScope(SearchControls.SUBTREE_SCOPE);  
  9.      try {  
  10.         NamingEnumeration<SearchResult> ne = dirContext.search(baseDN, filter , cons);  
  11.         SearchResult entry = null;  
  12.         for(;ne.hasMore();){  
  13.             entry = ne.next();  
  14.             showEntry(entry);  
  15.         }                     
  16.     } catch (NamingException e) {  
  17.         e.printStackTrace();  
  18.     }  
  19. }  


相关补充 

javax.naming.Name对象说明 
在API中,我们常常见到对LDAP上下文条目有两种参数形式,一种是大家都熟悉的String参数,如: String baseDN = "ou=People,dc=jsoso ,dc=net"; 
另一种是使用javax.naming.Name类型的参数,那么Name类和String有什么区别呢? 
简单的说,Name是对String类DN的封装,它把一个完整的DN字窜分解成了RDN的list。这个list的顺序刚好和String相反。就拿"ou=People,dc=jsoso ,dc=net"为例,Name中的RDN顺序是[0]=net,[1]=jsoso,[2]=People。这样做的好处是更方便对Name进行操作,比如取其前缀或者后缀。 

SearchControls SCOPE补充说明 
 

LDAP filter语法补充说明 
filter的运算符 
 
filter布尔运算符 
 

搜索过滤器示例 

  • 下列过滤器将搜索包含一个或多个 manager 属性值的条目。这也称为存在搜索: manager=*
  • 下列过滤器将搜索包含通用名 Ray Kultgen 的条目。这也称为等价搜索:cn=Ray Kultgen
  • 下列过滤器返回所有不包含通用名 Ray Kultgen 的条目:(!(cn=Ray Kultgen))
  • 下列过滤器返回的所有条目中都有包含子字符串 X.500 的说明属性:description=*X.500*
  • 下列过滤器返回所有组织单元为 Marketing 且说明字段中不包含子字符串 X.500 的条目: (&(ou=Marketing)(!(description=*X.500*)))
  • 下列过滤器返回所有组织单元为 Marketing 且 manager 为 Julie Fulmer 或 Cindy Zwaska 的条目: (&(ou=Marketing)(|(manager=cn=Julie Fulmer,ou=Marketing,dc=siroe,dc=com)(manager=cn=Cindy Zwaska,ou=Marketing,dc=siroe,dc=com)))
  • 下列过滤器返回所有不代表人员的条目: (!(objectClass=person))
  • 下列过滤器返回所有不代表人员且通用名近似于 printer3b 的条目:(&(!(objectClass=person))(cn~=printer3b))


 

分享到:
评论

相关推荐

    Sun Directory Server(Ldap)实例创建手册

    Sun Directory Server,也被称为Sun One Directory Server,是Sun Microsystems(现已被Oracle公司收购)开发的一款强大的 Lightweight Directory Access Protocol (LDAP) 服务器。LDAP是一种开放标准的目录服务协议...

    SUN Directory Server 培训资料

    SUN Directory Server是Sun Microsystems(现已被Oracle收购)开发的一款强大的 Lightweight Directory Access Protocol (LDAP) 目录服务器,主要用于管理和存储组织的各种网络资源信息,如用户账号、权限、配置数据...

    Sun One Directory Server(LDAP)安装和调整指南

    3. 从协议衍化上阐述LDAP,它是“目录访问协议DAP——ISO X.500”的衍生,简化了DAP协议,提供了轻量级的基于TCP/IP协议的网络访问,降低了管理维护成本,但保持了强壮且易于扩充的信息框架。LDAP的应用程序可以很...

    Sun ONE Directory Server

    Sun ONE (Open Network Environment) Directory Server,是Sun Microsystems公司(现已被甲骨文公司收购)推出的一款企业级的目录服务软件。它是一个基于 Lightweight Directory Access Protocol (LDAP) 的目录服务...

    ldap详解——ibm tivoli directory server从入门到精通 part3

    《ldap详解——ibm tivoli directory server从入门到精通》以ibm tivoli directory server(tds)软件产品为基础,针对ldap目录服务进行了全面、系统的阐述和介绍。全书涵盖了ldap的原理、安装、配置、管理、设计、...

    com.sun.jndi.ldap.jar

    3. 确保在代码中正确地使用JNDI LDAP API,例如: ```java import javax.naming.*; import javax.naming.ldap.*; public class LdapExample { public static void main(String[] args) { try { // 创建初始上...

    Sun One Directory Server 5.2

    Sun One Directory Server 5.2 是一款由Sun Microsystems(后被Oracle公司收购)开发的企业级目录服务软件。这款产品在2000年代初期广泛应用于组织的网络基础设施中,用以管理和存储用户身份、权限和其他元数据。...

    Sun Java System Directory Server.5.2

    Sun Java System Directory Server 5.2 是一款由Sun Microsystems开发的企业级 Lightweight Directory Access Protocol (LDAP) 服务器。作为目录服务的核心组件,它被设计用于存储、管理和检索大量结构化数据,如...

    Sun Directory Server Install Tutorial

    Sun Directory Server 是一款基于 Lightweight Directory Access Protocol (LDAP) 的目录服务软件,由 Sun Microsystems 开发。在进行 Sun Directory Server 的安装教程中,有几个关键的知识点是必须了解的,这些...

    DzzOffice AD/LDAP账户认证

    DzzOffice 安装和升级插件说明(详细教程请在DzzOffice 笔记中查看): 下载并解压插件后,请将解压后的插件文件夹以"LDAP"命名的方式放置在网站的"dzz"目录下(若该目录下已存在同名文件夹,请先删除原文件夹后再...

    LDAP学习笔记相关资料

    LDAP学习笔记 LDAP,全称为轻量级目录访问协议,是一种用于访问和管理分布式目录服务的网络协议。它源于X.500标准,但在设计上更为轻便且可定制,支持TCP/IP通信,这对于互联网访问至关重要。目录服务主要用于快速...

    LDAP API 文档

    Sun Directory Server_LDAP LDAP的英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP。它是基于X.500标准的,但是简单多了并且可以根据需要定制。与X.500不同,LDAP支持TCP/IP,这对访问Internet...

    Sun Directory

    Sun Java System Directory,也称为Sun Directory Server或OpenDS,是一款由Sun Microsystems开发的高性能、可扩展的LDAP(轻量目录访问协议)服务器。它支持高可用性和大规模数据处理,被广泛应用于企业环境中作为...

    配置IBM Tivoli Directory Server为Cognos的LDAP认证源.

    配置IBM Tivoli Directory Server(ITDS)作为Cognos的LDAP认证源是实现企业级安全性和用户管理的重要步骤。这一过程不仅提升了系统的安全性,还促进了Cognos BI(Business Intelligence)与IBM Tivoli安全架构之间...

    备用DNS服务器:可选的SQL / LDAP后端Alternative DNS Servers: Optional SQL/LDAP Back-Ends

    在讨论DNS服务器的配置与部署时,会涉及到DNS信息存储的多种方式,其中一种方式是利用LDAP目录服务或SQL数据库。这种做法主要是为了增强DNS系统的健壮性和扩展性。LDAP目录服务是一种用于存储和检索信息的轻型目录...

    ldap样例数据文件

    ldap样例数据,可用来导入。

    loginServer CAS / josso / LDAP / RBAC / ACL

    3. **LDAP(Lightweight Directory Access Protocol)**:LDAP 是一种用于访问和管理分布式目录服务的标准协议。在企业环境中,LDAP 通常用于存储用户账户信息和权限,便于进行身份验证和授权。登录服务器可以通过 ...

    Apache Directory Server使用指南

    Apache Directory Server 是一个基于 Java 语言的开源 LDAP 服务器,由 Apache 软件基金会开发和维护。该服务器提供了一个完整的目录解决方案,包括目录服务器、目录工具和其他相关组件。 目录服务器简介 Apache ...

    debian下ldap服务器配置

    安装完成后,需要编辑配置文件 `/etc/ldap/slapd.conf`。使用以下命令打开编辑器: ``` # vim /etc/ldap/slapd.conf ``` 在编辑器中,添加以下内容: ``` include /etc/ldap/schema/core.schema include /etc/ldap/...

    适用于 Python 的 LDAP 客户端 API 仅供学习参考用代码.zip

    Python 的 LDAP 客户端 API 是一种用于与 Lightweight Directory Access Protocol (LDAP) 服务器交互的工具,它允许程序员在 Python 应用程序中执行 LDAP 操作,如查询、添加、修改和删除目录服务中的条目。...

Global site tag (gtag.js) - Google Analytics