ldap的学习

本文详细介绍了LDAP的基本概念,包括DN、DC、OU等,并通过Java代码示例展示了如何实现LDAP的连接、查询、增删改查等操作。同时,还探讨了LDAP的设计理念,特别是对象类(objectClass)的概念及其实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、ldap是什么?

Light Directory Access Protocol,轻量级目录访问协议.

dn (Distinguished Name):一条记录的位置
dc :一条记录所属区域
ou :一条记录所属组织
cn/uid:一条记录的名字/ID

 

LDAP中,schema用来指定一个目录中所包含的objects的类型(objectClass)以及每一个objectClass中的各个必备(mandatory)和可选(optional)的属性(attribute)。因此,Schema是一个数据模型,它被用来决定数据怎样被存储,被跟踪的数据的是什么类型,存储在不同的Entry下的数据之间的关系。schema需要在主配置文件slapd.conf中指定,以用来决定本目录中使用到的objectClass。管理员可以自己设计制定schema,一般包括属性定义(AttributeDefinition)、类定义(ClassDefinition)以及语法定义(SyntaxDefinition)等部分。  可以通过ldap的admin console来增加用户自定义的objectclass。
   

 二、ldap的java代码(Sun Java(TM) System Directory Server 5.2)

ldap连接池的网址:http://java.sun.com/products/jndi/tutorial/ldap/connect/config.html

private static DirContext dc;

连接:

public static void connect(){
  String dn="cn=Directory Manager"; //登陆用户

String password="";//dn的密码
  String url="ldap://ip:389/"; //ldap server的host
  String   root="dc=ahhexin,dc=com"; //basedn
  Hashtable env = new Hashtable();
  env.put(DirContext.INITIAL_CONTEXT_FACTORY,
    "com.sun.jndi.ldap.LdapCtxFactory");
  env.put(DirContext.PROVIDER_URL, url);
  env.put(DirContext.SECURITY_AUTHENTICATION, "simple");  //Use simple authentication 

  if (dn != null) {
   env.put(DirContext.SECURITY_PRINCIPAL, dn);   
   env.put(DirContext.SECURITY_CREDENTIALS, password);
  }
  try {   
   dc = new InitialDirContext(env);
   System.out.println("认证成功");
     } catch (NamingException ex) {
     System.out.println("认证失败:" + ex.getMessage()+ex.getStackTrace());
   dc = null;
  }      
 }

在ldap认证时候,提示认证失败,查找原因方法:1、首先到到ldap server那台机器上用命令增加dn,具体是:

ldapadd -x -D "cn=Directory Manager" -w password,然后回车,如果没有报密码或者错误,说明此dn是可以登陆的。

2、检查网络,看看防火墙设置,在你的机器上运行:telnet ldapserver的ip  ldap的端口,如果不通,就是网络问题或者机器配置问题。(我的ldap client跟ldap server不在一台机器上)。

 

ldap查询:

/**
  * 查询条件:basedn,filter,searchControls
  * 查询结果可能有more than one entry ,利用循环来取entry,每个entry存放结构是SearchResult中
  * 每个entry有:dn和attributes
  * 每个attributes有more than one attribute
  * 每个attribute有一个attriId,and more than one value
  * 得到每个value值
  */
 public static void selLdap(){
  ArrayList listAll = new ArrayList();  
  String basedn="dc=ahhexin,dc=com";
  String filter="objectClass=*";
  SearchControls   cons = new SearchControls();

//查询有三个scope:OBJECT_SCOPE,ONELEVEL_SCOPE,SUBTREE_SCOPE
  cons.setSearchScope(cons.SUBTREE_SCOPE); 
  NamingEnumeration ne = null;
  NamingEnumeration subne=null;  
  try {
   ne=dc.search(basedn, filter, cons);
   while(ne.hasMore()){
    ArrayList ldapinfo =new ArrayList();
    SearchResult sr=(SearchResult)ne.next();
    String dn=sr.getName();
    System.out.println();
    System.out.println("dn: "+dn); //这个地方dn是rdn
    ldapinfo.add(dn);
    Attributes  ats = sr.getAttributes();
    subne=ats.getAll();
    while(subne.hasMore()){
     Attribute at = (Attribute)subne.next();
     String attrId=at.getID();      
     NamingEnumeration valNe=at.getAll();
     while(valNe.hasMore()){
      Object attrVal = valNe.nextElement();
      System.out.println(attrId+": "+ attrVal);
      if(attrVal instanceof String)
       ldapinfo.add(attrId+": "+ attrVal);    
      else
       ldapinfo.add(attrId+": "+ new String((byte[])attrVal));              
     }
    }
    listAll.add(ldapinfo);
   }
  } catch (NamingException e) {
   System.out.println("查询entries失败");
   e.printStackTrace();
  }
 } 

ldap增加dn

/**
  * 填写属性和dn,然后利用createSubcontext创建即可
  *
  */ 
 public static void addLdapEntry(){
  String basedn="dc=ahhexin,dc=com";
  String dn="uid=bjensen"+","+basedn; 

  BasicAttributes attrs =new BasicAttributes();
  BasicAttribute objectclass = new BasicAttribute("objectClass");
  objectclass.add("top");
  objectclass.add("person");
  objectclass.add("organizationalPerson");
  objectclass.add("inetOrgPerson");
  attrs.put(objectclass);
  attrs.put("cn", "Barbara Jensen");
  attrs.put("sn", "Jensen");
  attrs.put("givenName", "Barbara");
  attrs.put("title", "manager, product development");
  attrs.put("uid", "bjensen");
  attrs.put("mail", "zhangsan.com");
  try {
   dc.createSubcontext(dn, attrs);
  } catch (NamingException e) {
   System.out.println("增加entry失败");
   e.printStackTrace();
  }  
 }

ldap修改dn的属性

/**
  * 修改属性
  */
 public static void modLdap(){
  String basedn="dc=ahhexin,dc=com";
  String dn="uid=bjensen"+","+basedn;
  /**
   * 增加属性,如果增加的属性存在,则增加属性的值,如果此值已经存在,则报错
   */
  BasicAttributes addattrs =new BasicAttributes();
  
  addattrs.put("roomNumber", "0209"); 
  addattrs.put("carLicense", "6ABC246");
  try {
   dc.modifyAttributes(dn, DirContext.ADD_ATTRIBUTE, addattrs);
  } catch (NamingException e1) {
   System.out.println("增加属性失败");
   e1.printStackTrace();
  }
  /**
   * 替换属性,替换属性如果不存在,就增加次属性
   */
  BasicAttributes modattrs =new BasicAttributes();
  BasicAttribute modattr = new BasicAttribute("mail");
  modattr.add("tt@hotmail.com");
  modattr.add("ee@hotmail.com");
  modattrs.put(modattr);
  modattrs.put("givenName", "Barbara1"); 
  try {
   dc.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, modattrs);
  } catch (NamingException e) {
   System.out.println("修改属性失败");
   e.printStackTrace();
  }
  /**
   * 删除属性,删除的属性需要存在,否则会报错
   */
  
  BasicAttributes delattrs =new BasicAttributes();
  delattrs.put("title", null); 
  try {
   dc.modifyAttributes(dn, DirContext.REMOVE_ATTRIBUTE, delattrs);
  } catch (NamingException e) {
   System.out.println("删除属性失败");
   e.printStackTrace();
  }         
 }
 

ldap修改dn的名称

/**
  * 修改dn的名称,并且属性uid的值也改变了

*  如果dn是非叶子节点,是不允许修改的

* 修改rdn,不能修改dn中相对路径的值,比如A是ou=people1中的孩子,现在想A改成ou=people2中的孩子,此中情况不能直接修改dn,需要在ou=people1中删除A,然后到ou=people2中增加A
  *
  */
 public static void modifyLdapDn(){
  String basedn="dc=ahhexin,dc=com";
  String oldDn="uid=bjensen"+","+basedn;
  String newDn="uid=bjensennew"+","+basedn;
  try {
   dc.rename(oldDn, newDn);
  } catch (NamingException e) {
   System.out.println("修改dn名称失败");
   e.printStackTrace();
  }  
 }

 

ldap删除dn

/**
  * 删除dn,如果dn下面还有node,此删除操作失败
  */
 public static void delLdap(){ 
  String basedn="dc=ahhexin,dc=com";  
  String dn="uid=bjensennew"+","+basedn;
  try {
   dc.destroySubcontext(dn);
  } catch (NamingException e) {
   System.out.println("删除entry失败");
   e.printStackTrace();
  }
 }

ldap关闭连接

public static void close()
 {
  if(dc!=null)
   try {
    dc.close();
   } catch (NamingException e) {
    System.out.println("关闭dc认证失败");
    e.printStackTrace();
   }
 }

三、设计思考

  LDAP中,一条记录必须包含一个objectClass属性,且其需要赋予至少一个值。每一个值将用作一条LDAP记录进行数据存储的模板;模板中包含了一条记录中数个必须被赋值的属性和一系列可选的属性。
    objectClass有着严格的等级之分,最顶层的类是top和alias。例如,organizationalPerson这个objectClass隶属于Person,而Person又是top的子类。

    objectClass大致分为三类:结构型的(如:person和organizationUnit)、辅助型的(如:extensibeObject)和抽象型的(这类不能直接使用)。官方定义的objectClass为http://ldap.akbkhome.com/index.php/objectclass.html

思考:ldap的objectclass的设计是inherit的,而我们在做ldap设计过程用的是关系型数据库bcd范式的设计思想,而ldap server中的数据存储方式跟关系型数据库存储方式不一样,我理解的ldap的存储方式是树型结构存储方式,所以ldap的查找是很高效的。


 

四、不错的ldap网址:http://blog.chinaunix.net/u/4206/showart_286820.html

http://www.ldapman.org/articles/tree_design.html

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值