Java操作Ldap

来源:互联网 发布:怎样进去网络黑市 编辑:程序博客网 时间:2024/05/19 12:39

页面布局基本写完了,那么开始正式写业务逻辑,当时的需求是这样的:把Ldap的树搬到我们的项目中。

Ldap是什么?完全不知道,没办法,查资料吧。

要把Ldap的树搬到我们的页面中,大致上分这几步:1. 连接Ldap,也叫Ldap认证; 2. 读取Ldap信息; 3. 存到本地数据库。


连接Ldap:Java提供了两个接口去操作Ldap,一个是DirContext,另一个是LdapContext,后者继承前者。Spring也提供了一个操作Ldap的接口,没用过,略过不提。

我在项目中用的是LdapContext。

认证的代码我都是从网上找来的,相关资料十分多,大概贴下代码吧

Hashtable env = new Hashtable();// 记录工JNDI工厂env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");// LDAP的地址,要根据LDAP服务器IP进行修改,389是LDAP的默认端口env.put(Context.PROVIDER_URL, "192.168.0.16:389");// 认证方式为默认的simple,即用户名/密码env.put(Context.SECURITY_AUTHENTICATION, "simple");// LDAP的账户名,一般是这样的格式:Dn : cn=userA,dc=hunan,dc=com ,根据LDAP的配置情况来env.put(Context.SECURITY_PRINCIPAL, Dn);// 对应上面账户的密码env.put(Context.SECURITY_CREDENTIALS, password);try {ldapContext = new InitialLdapContext(env, null);} catch (NamingException e) {e.printStackTrace();Log.info("连接ldap服务器失败");}
没什么好多解释的,注释还算详细。

如果连接时候失败了,或者控制台报错Ldap相关的错误,建议大家去这个网站看看:

http://wiki.servicenow.com/index.php?title=LDAP_Error_Codes


认证成功了,那么就要开始操作Ldap了。

一开始我一直很费解,一个Ldap中的节点(也叫条目,或者entry),在Java中到底该用哪个对象来表示?需要自己定义一个吗?

所幸,Java提供了这个类 : SearchResult

Ldap相较于关系型数据库,它特别优化了查询的方法,所以在Java代码中,查询是一个比较主要的操作。毕竟,一般有Ldap的公司不会通过你Java写的这个项目去增删改自己公司的Ldap的条目。

先上代码再说:


<span style="white-space:pre"></span>/** * 根据给定Entry的区别名,找到Entry,SearchResult实际上是Ldap树中的一个Entry</br> * 不设置返回值,默认返回Entry下的所有属性 * @param entryDN 区别名</br> * @param filter 过滤条件 如:(objectclass=*) (objectclass=user)...</br> * @param 搜索范围:0 : 搜索该节点本身,返回一条数据 *                  1 : 搜索该节点下的所有子节点(不包含子节点的子节点) *                  2 : 搜索该节点下的所有子节点(包括子节点的子节点) * @return entry */public List<SearchResult> findEntry(String entryDN, String scope, String filter) {List<SearchResult> entryList = new ArrayList<SearchResult>();SearchControls sc = new SearchControls();if (entryDN == null) {Log.info("entryDN为空");return null;}if ("0".equals(scope)) {sc.setSearchScope(SearchControls.OBJECT_SCOPE);} else if ("1".equals(scope)) {sc.setSearchScope(SearchControls.ONELEVEL_SCOPE);} else if ("2".equals(scope)) {sc.setSearchScope(SearchControls.SUBTREE_SCOPE);} else {Log.info("搜索范围[0, 1, 2]");return null;}if (filter==null || filter.equals("")) {Log.info("未设定过滤器");return null;}try {NamingEnumeration<SearchResult> entries = ldapContext.search(entryDN, filter, sc);SearchResult entry = null;// 如果使用hasMore()方法会报错,因为hasMore()方法会抛出异常while (entries.hasMoreElements()) {entry = entries.next();entryList.add(entry);}entries.close();return entryList;} catch (NamingException e) {e.printStackTrace();Log.info("依据条件查找条目失败");}return null;}

可能代码不够严谨,但目前我也只能做到这一步了。

代码中加了注解的就不细说了。

NamingEnumeration这个类是一个集合,我基本上把它当作了一个List或这Set来看待,当然他们的本质是不同的,但是没有仔细研究,就不说什么影响别人了。


在项目中还比较常用的一个方法,就是查询这个条目的属性了,代码如下:

<span style="white-space:pre"></span>/** * 通过指定的entry和属性ID,取得对应的属性,前提需要知道有哪些属性ID * 如:"objectclass", "distinguishedName", "name" 等 * 每次只能取得一条数据 * @param entry 条目 * @param arrtID 属性ID * @return str1 */public String findItemByEntryNew(SearchResult entry, String attrID) {if (entry == null) {return null;}if (attrID==null || attrID.equals("")) {Log.info("属性ID不能为空");return null;}Attributes attrs = entry.getAttributes();if (attrs != null) {Attribute attr = attrs.get(attrID);if (attr != null) {String str = attr.toString();String[] str1 = str.split(": ");return str1[str1.length-1];}return null;}return null;}

比方说我现在已经得到了一个Ldap树节点,我想知道这个节点的dn是什么,或者他的objectclass中包含哪些属性,那么用这个方法就刚好了。

代码中的Attributes类,是一个属性集,它里面会有dn=...., objectclass=..., name=..., objectGUID=... 不一一列举了。

需要说明一下最后剪切字符串的地方,因为不剪切的话它会返回:distinguishedName: CN=...,CN=...,DC=...,DC=... , 这样不方便我后面的操作,所以直接剪切掉了。


暂时写到这。


0 0