JAVA操作LDAP总结「建议收藏」

Java (119) 2023-07-08 14:12

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说JAVA操作LDAP总结「建议收藏」,希望能够帮助你!!!。

一、LDAP概念

LDAP的全称为Lightweight Directory Access Protocol(轻量级目录访问协议), 基于X.500标准, 支持 TCP/IP。

LDAP目录为数据库,通过LDAP服务器(相当于DBMS)处理查询和更新, 以树状的层次结构来存储数据,相对关系型数据库, LDAP主要是优化数据读取的性能,适用于比较少改变、跨平台的信息。

二、Softerra LDAP Administrator

下载安装软件,并配置LDAP

JAVA操作LDAP总结「建议收藏」_https://bianchenghao6.com/blog_Java_第1张

DN:Distinguished Name 唯一标识一条记录的路径,Base DN为基准DN,指定LDAP search的起始DN,即从哪个DN下开始搜索,RDN为叶子结点本身的名字。

DC:Domain Component 一条记录所属区域

OU:Organization Unit 组织单元

CN/UID:一条记录的名字/ID

三、在JAVA中应用LDAP

1、spring配置文件

<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">

<constructor-arg ref="ldapcontextSource" />

</bean>

<bean id="ldapcontextSource" class="org.springframework.ldap.core.support.LdapContextSource">

<property name="url" value="${LdapConnHost}" /> <!—例: LdapConnHost=ldap://10.190.123.123 -->

<property name="userDn" value="${LdapConnUser}" /><!—例: LdapConnUser=cn=root -->

<property name="password" value="${LdapConnPwd}" /><!—例: LdapConnPwd=111111 -->

<property name="base" value="${LdapBaseDn}" /> <!—Base DN 例: LdapBaseDn=DC=FJTIC -->

<property name="pooled" value="false" />

</bean>

四、JAVA代码

4.1spring版本

 1 package com.test.dao;
 2 
 3 import java.beans.PropertyDescriptor;
 4 import java.lang.reflect.Field;
 5 import java.lang.reflect.InvocationTargetException;
 6 import java.lang.reflect.Method;
 7 import java.util.ArrayList;
 8 import java.util.List;
 9 import javax.naming.Name;
 10 import javax.naming.NamingEnumeration;
 11 import javax.naming.NamingException;
 12 import javax.naming.directory.Attribute;
 13 import javax.naming.directory.Attributes;
 14 import javax.naming.directory.BasicAttribute;
 15 import javax.naming.directory.BasicAttributes;
 16 import javax.naming.directory.ModificationItem;
 17 import org.apache.commons.beanutils.BeanUtils;
 18 import org.springframework.beans.factory.annotation.Autowired;
 19 import org.springframework.dao.EmptyResultDataAccessException;
 20 import org.springframework.ldap.core.ContextMapper;
 21 import org.springframework.ldap.core.DirContextAdapter;
 22 import org.springframework.ldap.core.DirContextOperations;
 23 import org.springframework.ldap.core.DistinguishedName;
 24 import org.springframework.ldap.core.LdapTemplate;
 25 import org.springframework.ldap.core.support.AbstractContextMapper;
 26 import org.springframework.ldap.filter.AndFilter;
 27 import org.springframework.ldap.filter.EqualsFilter;
 28 import org.springframework.ldap.filter.OrFilter;
 29 import org.springframework.stereotype.Component;
 30 import com.surekam.model.Person;
 31 import com.surekam.utils.DateCl;
 32 import com.surekam.utils.StringUtil;
 33 
 34 @Component
 35 public class UserDAOL {
 36 @Autowired
 37 private LdapTemplate ldapTemplate;
 38 
 39 /**
 40 *
 41 * @Description: 添加
 42 *
 43 */
 44 public boolean addPerson(Person person) {
 45 boolean flag = false;
 46 Name dn = buildUDn(person.getUid());
 47 Attributes buildAddAttributes = buildAddAttributes(person);
 48 ldapTemplate.bind(dn, null, buildAddAttributes);
 49 flag = true;
 50 return flag;
 51 }
 52 
 53 /**
 54 *
 55 * @Description: 修改
 56 *
 57 */
 58 public boolean updatePerson(Person person) {
 59 boolean flag = false;
 60 Name dn = buildUDn(person.getUid());
 61 ModificationItem[] modificationItem = buildModifyAttributes(person);
 62 ldapTemplate.modifyAttributes(dn, modificationItem);
 63 flag = true;
 64 return flag;
 65 }
 66 
 67 /**
 68 *
 69 * 多条件获取用户
 70 * 
 71 */
 72 public List<Person> getPersonByOu(String ou, String level) {
 73 AndFilter filter = new AndFilter();
 74 OrFilter orFilter1 = new OrFilter();
 75 if ("处级干部".equals(level)) {
 76 orFilter1.or(new EqualsFilter("cuadministrativelevels", "aa"));
 77 orFilter1.or(new EqualsFilter("cuadministrativelevels", "bb"));
 78 orFilter1.or(new EqualsFilter("cuadministrativelevels", "cc"));
 79 orFilter1.or(new EqualsFilter("cuadministrativelevels", "dd"));
 80 }
 81 if ("普通员工".equals(level)) {
 82 orFilter1.or(new EqualsFilter("cuadministrativelevels", "ee"));
 83 orFilter1.or(new EqualsFilter("cuadministrativelevels", "ff"));
 84 orFilter1.or(new EqualsFilter("cuadministrativelevels", "gg"));
 85 }
 86 OrFilter orFilter2 = new OrFilter();
 87 orFilter2.or(new EqualsFilter("departmentnumber", ou));
 88 orFilter2.or(new EqualsFilter("cutransferdnumber", ou));
 89 filter.and(orFilter2);
 90 filter.and(orFilter1);
 91 System.out.println(filter.toString());
 92 List<Person> list = ldapTemplate.search("cn=users,dc=hq", filter
 93 .encode(), new PersonContextMapper());
 94 return list;
 95 }
 96 
 97 
 98 /**
 99 *
100 * 生成用户DN
101 * 
102 * @return uid=123455,cn=users,dc=hq
103 */
104 private Name buildUDn(String urdn) {
105 DistinguishedName dn = new DistinguishedName("");
106 dn.add("dc", "hq");
107 dn.add("cn", "users");
108 dn.add("uid", urdn);
109 return dn;
110 }
111 
112 /**
113 *
114 * 组织查询结果
115 * 
116 */
117 public static class PersonContextMapper implements ContextMapper {
118 public Object mapFromContext(Object ctx) {
119 if (ctx == null)
120 return new Person();
121 DirContextAdapter context = (DirContextAdapter) ctx;
122 Person per = new Person();
123 Attributes attrs = context.getAttributes();
124 NamingEnumeration results = attrs.getAll();
125 Class c = per.getClass();
126 while (results.hasMoreElements()) {
127 try {
128 Attribute attr = (Attribute) results.next();
129 String value = attr.get().toString();
130 if (StringUtil.isNotEmpty(value)) {
131 String fieldName = attr.getID();
132 if ("objectclass".equals(fieldName.toLowerCase())) {
133 continue;
134 }
135 Field field = c.getDeclaredField(fieldName
136 .toLowerCase());
137 Class fieldClazz = field.getType();
138 /*
139 * 如果属性条数大于1,那就是多值属性 attr.getAttributeDefinition()
140 * 获取多值属性的方法没找到
141 */
142 if (fieldClazz.isAssignableFrom(List.class)) { // 属性值数大于1
143 NamingEnumeration values = attr.getAll(); // 获取所有值
144 // LDAP中的多值属性只会是String类型
145 List<String> list = new ArrayList<String>();
146 while (values.hasMoreElements()) {
147 list.add(values.next().toString());
148 }
149 BeanUtils.setProperty(per, fieldName.toLowerCase(),
150 list);
151 } else {
152 // 普通属性
153 BeanUtils.setProperty(per, fieldName.toLowerCase(),
154 value);
155 }
156 }
157 } catch (IllegalAccessException e) {
158 e.printStackTrace();
159 } catch (InvocationTargetException e) {
160 e.printStackTrace();
161 } catch (NamingException e) {
162 e.printStackTrace();
163 } catch (SecurityException e) {
164 // TODO Auto-generated catch block
165 e.printStackTrace();
166 } catch (NoSuchFieldException e) {
167 // TODO Auto-generated catch block
168 e.printStackTrace();
169 }
170 }
171 per.setDn(context.getNameInNamespace());
172 return per;
173 }
174 }
175 
176 /**
177 *
178 * 组织添加数据数据
179 * 
180 */
181 @SuppressWarnings("unchecked")
182 private Attributes buildAddAttributes(Person p) {
183 Attributes attrs = new BasicAttributes();
184 BasicAttribute ocattr = new BasicAttribute("objectclass");
185 ocattr.add("top");
186 ocattr.add("person");
187 ocattr.add("organizationalPerson");
188 ocattr.add("inetOrgPerson");
189 ocattr.add("FJTicPerson");
190 attrs.put(ocattr);
191 Class c = p.getClass();
192 Field[] fields = c.getDeclaredFields();
193 for (int i = 0; i < fields.length; i++) {
194 try {
195 Class fieldClazz = fields[i].getType();
196 String fieldName = fields[i].getName(); // 获得属性名
197 String fieldVlue = BeanUtils.getProperty(p, fieldName); // 获得属性值
198 /*
199 * 判断属性是否要过滤,例如修改时间之类的字段LDAP是没有的 判断属性值是否为空,在这里过滤了所有null和""
200 * 增加操作中不存在主动设置某个值为空的情况 所以只需要处理有值属性
201 */
202 if (checkfieldName(fieldName) || StringUtil.isEmpty(fieldVlue))
203 continue;
204 /*
205 * 多值属性的处理 如果多值属性为空,那么增加的时候就不会增加值进去
206 */
207 if (fieldClazz.isAssignableFrom(List.class)) { // 集合属性
208 BasicAttribute ocattr1 = new BasicAttribute(fieldName);
209 PropertyDescriptor pd = new PropertyDescriptor(fieldName, c);
210 Method getMethod = pd.getReadMethod();// 获得get方法
211 List list = (List) getMethod.invoke(p);// 执行get方法返回一个Object
212 for (Object object : list) {
213 ocattr1.add(object);
214 }
215 attrs.put(ocattr1);
216 } else {
217 attrs.put(fieldName, fieldVlue);
218 }
219 } catch (Exception e) {
220 e.printStackTrace();
221 }
222 }
223 return attrs;
224 
225 }
226 
227 /**
228 *
229 * 组织修改数据
230 * 
231 */
232 @SuppressWarnings("unchecked")
233 private ModificationItem[] buildModifyAttributes(Person p) {
234 ArrayList<ModificationItem> attrs = new ArrayList<ModificationItem>();
235 Class c = p.getClass();
236 Field[] fields = c.getDeclaredFields();
237 for (Field field : fields) {
238 try {
239 Class fieldClazz = field.getType();
240 String fieldName = field.getName(); // 获得属性名
241 String fieldValue = BeanUtils.getProperty(p, fieldName);
242 /*
243 * 判断属性是否要过滤,例如修改时间之类的字段LDAP是没有的 判断属性值是否为空,在这里过滤了所有null和""
244 * 要置空的属性通过识别特殊属性值:delAtr 在后面做重新置空操作
245 */
246 if (checkfieldName(fieldName) || StringUtil.isEmpty(fieldValue))
247 continue;
248 BasicAttribute basicAttr = new BasicAttribute(fieldName);
249 /*
250 * 多值属性的处理 如果传递一个空的list,那么修改的时候就会清空多值属性 (new ArrayList<String>())
251 */
252 if (fieldClazz.isAssignableFrom(List.class)) { // 如果是集合属性
253 PropertyDescriptor pd = new PropertyDescriptor(fieldName, c);
254 Method getMethod = pd.getReadMethod();// 获得get方法
255 List list = (List) getMethod.invoke(p);// 执行get方法返回一个Object
256 for (Object object : list) {
257 basicAttr.add(object);
258 }
259 } else {
260 /*
261 * 判断删除标记来对值进行置空 传递过来的对象中有些属性没有做修改就传递了"" 有些是要修改为 ""
262 * 所以在上面要过滤所有 "" 属性,避免将不修改的参数全都置空了 然后通过识别要修改参数的特有值来判断是否主动置空
263 * 如果add一个""进去,那么在LDAP中依然会显示
264 * 如果不给值,由BasicAttribute自动授予空值,那么在LDAP中就不显示了
265 */
266 if ("delAtr".equals(fieldValue)) {
267 basicAttr.add(""); // 置空属性
268 } else {
269 basicAttr.add(fieldValue);// 有值属性
270 }
271 }
272 // 替换条目
273 attrs.add(new ModificationItem(
274 DirContextAdapter.REPLACE_ATTRIBUTE, basicAttr));
275 } catch (Exception e) {
276 e.printStackTrace();
277 }
278 }
279 return attrs.toArray(new ModificationItem[attrs.size()]);
280 }
281 
282 /**
283 *
284 * 过滤默认值字段
285 * 
286 */
287 private static boolean checkfieldName(String fieldName) {
288 String[] check = new String[] { "id", "status", "createtime",
289 "updatetime", "dn" };
290 for (int i = 0; i < check.length; i++) {
291 if (check[i].equalsIgnoreCase(fieldName))
292 return true;
293 }
294 return false;
295 }
296 }

4.2普通实现

1 package com.smnpc.util;
 2 
 3 import java.util.Hashtable;
 4 import java.util.Vector;
 5 
 6 import javax.naming.Context;
 7 import javax.naming.NamingEnumeration;
 8 import javax.naming.NamingException;
 9 import javax.naming.directory.Attribute;
 10 import javax.naming.directory.Attributes;
 11 import javax.naming.directory.BasicAttribute;
 12 import javax.naming.directory.BasicAttributes;
 13 import javax.naming.directory.DirContext;
 14 import javax.naming.directory.InitialDirContext;
 15 import javax.naming.directory.ModificationItem;
 16 import javax.naming.directory.SearchControls;
 17 import javax.naming.directory.SearchResult;
 18 import javax.naming.ldap.LdapContext;
 19 
 20 /**
 21 * Java通过Ldap操作AD的增删该查询
 22 * 
 23 * @author guob
 24 */
 25 
 26 public class LdapbyUser {
 27 DirContext dc = null;
 28 String root = "dc=example,dc=com"; // LDAP的根节点的DC
 29 
 30 /**
 31 * 
 32 * @param dn类似于"CN=RyanHanson,dc=example,dc=com"
 33 * @param employeeID是Ad的一个员工号属性
 34 */
 35 public LdapbyUser(String dn, String employeeID) {
 36 init();
 37 // add();//添加节点
 38 // delete("ou=hi,dc=example,dc=com");//删除"ou=hi,dc=example,dc=com"节点
 39 // renameEntry("ou=new,o=neworganization,dc=example,dc=com","ou=neworganizationalUnit,o=neworganization,dc=example,dc=com");//重命名节点"ou=new,o=neworganization,dc=example,dc=com"
 40 // searchInformation("dc=example,dc=com", "",
 41 // "sAMAccountName=guob");//遍历所有根节点
 42 modifyInformation(dn, employeeID);// 修改
 43 // Ldapbyuserinfo("guob");//遍历指定节点的分节点
 44 close();
 45 }
 46 
 47 /**
 48 * 
 49 * Ldap连接
 50 * 
 51 * @return LdapContext
 52 */
 53 public void init() {
 54 Hashtable env = new Hashtable();
 55 String LDAP_URL = "ldap://xxxx:389"; // LDAP访问地址
 56 String adminName = "example\\user"; // 注意用户名的写法:domain\User或
 57 String adminPassword = "userpassword"; // 密码
 58 env.put(Context.INITIAL_CONTEXT_FACTORY,
 59 "com.sun.jndi.ldap.LdapCtxFactory");
 60 env.put(Context.PROVIDER_URL, LDAP_URL);
 61 env.put(Context.SECURITY_AUTHENTICATION, "simple");
 62 env.put(Context.SECURITY_PRINCIPAL, adminName);
 63 env.put(Context.SECURITY_CREDENTIALS, adminPassword);
 64 try {
 65 dc = new InitialDirContext(env);// 初始化上下文
 66 System.out.println("认证成功");// 这里可以改成异常抛出。
 67 } catch (javax.naming.AuthenticationException e) {
 68 System.out.println("认证失败");
 69 } catch (Exception e) {
 70 System.out.println("认证出错:" + e);
 71 }
 72 }
 73 
 74 /**
 75 * 添加
 76 */
 77 public void add(String newUserName) {
 78 try {
 79 BasicAttributes attrs = new BasicAttributes();
 80 BasicAttribute objclassSet = new BasicAttribute("objectClass");
 81 objclassSet.add("sAMAccountName");
 82 objclassSet.add("employeeID");
 83 attrs.put(objclassSet);
 84 attrs.put("ou", newUserName);
 85 dc.createSubcontext("ou=" + newUserName + "," + root, attrs);
 86 } catch (Exception e) {
 87 e.printStackTrace();
 88 System.out.println("Exception in add():" + e);
 89 }
 90 }
 91 
 92 /**
 93 * 删除
 94 * 
 95 * @param dn
 96 */
 97 public void delete(String dn) {
 98 try {
 99 dc.destroySubcontext(dn);
100 } catch (Exception e) {
101 e.printStackTrace();
102 System.out.println("Exception in delete():" + e);
103 }
104 }
105 
106 /**
107 * 重命名节点
108 * 
109 * @param oldDN
110 * @param newDN
111 * @return
112 */
113 public boolean renameEntry(String oldDN, String newDN) {
114 try {
115 dc.rename(oldDN, newDN);
116 return true;
117 } catch (NamingException ne) {
118 System.err.println("Error: " + ne.getMessage());
119 return false;
120 }
121 }
122 
123 /**
124 * 修改
125 * 
126 * @return
127 */
128 public boolean modifyInformation(String dn, String employeeID) {
129 try {
130 System.out.println("updating...\n");
131 ModificationItem[] mods = new ModificationItem[1];
132 /* 修改属性 */
133 // Attribute attr0 = new BasicAttribute("employeeID", "W20110972");
134 // mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
135 // attr0);
136 /* 删除属性 */
137 // Attribute attr0 = new BasicAttribute("description",
138 // "陈轶");
139 // mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE,
140 // attr0);
141 /* 添加属性 */
142 Attribute attr0 = new BasicAttribute("employeeID", employeeID);
143 mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr0);
144 /* 修改属性 */
145 dc.modifyAttributes(dn + ",dc=example,dc=com", mods);
146 return true;
147 } catch (NamingException e) {
148 e.printStackTrace();
149 System.err.println("Error: " + e.getMessage());
150 return false;
151 }
152 }
153 
154 /**
155 * 关闭Ldap连接
156 */
157 public void close() {
158 if (dc != null) {
159 try {
160 dc.close();
161 } catch (NamingException e) {
162 System.out.println("NamingException in close():" + e);
163 }
164 }
165 }
166 
167 /**
168 * @param base
169 * :根节点(在这里是"dc=example,dc=com")
170 * @param scope
171 * :搜索范围,分为"base"(本节点),"one"(单层),""(遍历)
172 * @param filter
173 * :指定子节点(格式为"(objectclass=*)",*是指全部,你也可以指定某一特定类型的树节点)
174 */
175 public void searchInformation(String base, String scope, String filter) {
176 SearchControls sc = new SearchControls();
177 if (scope.equals("base")) {
178 sc.setSearchScope(SearchControls.OBJECT_SCOPE);
179 } else if (scope.equals("one")) {
180 sc.setSearchScope(SearchControls.ONELEVEL_SCOPE);
181 } else {
182 sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
183 }
184 NamingEnumeration ne = null;
185 try {
186 ne = dc.search(base, filter, sc);
187 // Use the NamingEnumeration object to cycle through
188 // the result set.
189 while (ne.hasMore()) {
190 System.out.println();
191 SearchResult sr = (SearchResult) ne.next();
192 String name = sr.getName();
193 if (base != null && !base.equals("")) {
194 System.out.println("entry: " + name + "," + base);
195 } else {
196 System.out.println("entry: " + name);
197 }
198 
199 Attributes at = sr.getAttributes();
200 NamingEnumeration ane = at.getAll();
201 while (ane.hasMore()) {
202 Attribute attr = (Attribute) ane.next();
203 String attrType = attr.getID();
204 NamingEnumeration values = attr.getAll();
205 Vector vals = new Vector();
206 // Another NamingEnumeration object, this time
207 // to iterate through attribute values.
208 while (values.hasMore()) {
209 Object oneVal = values.nextElement();
210 if (oneVal instanceof String) {
211 System.out.println(attrType + ": "
212 + (String) oneVal);
213 } else {
214 System.out.println(attrType + ": "
215 + new String((byte[]) oneVal));
216 }
217 }
218 }
219 }
220 } catch (Exception nex) {
221 System.err.println("Error: " + nex.getMessage());
222 nex.printStackTrace();
223 }
224 }
225 
226 /**
227 * 查询
228 * 
229 * @throws NamingException
230 */
231 public void Ldapbyuserinfo(String userName) {
232 // Create the search controls
233 SearchControls searchCtls = new SearchControls();
234 // Specify the search scope
235 searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
236 // specify the LDAP search filter
237 String searchFilter = "sAMAccountName=" + userName;
238 // Specify the Base for the search 搜索域节点
239 String searchBase = "DC=example,DC=COM";
240 int totalResults = 0;
241 String returnedAtts[] = { "url", "whenChanged", "employeeID", "name",
242 "userPrincipalName", "physicalDeliveryOfficeName",
243 "departmentNumber", "telephoneNumber", "homePhone", "mobile",
244 "department", "sAMAccountName", "whenChanged", "mail" }; // 定制返回属性
245 
246 searchCtls.setReturningAttributes(returnedAtts); // 设置返回属性集
247 
248 // searchCtls.setReturningAttributes(null); // 不定制属性,将返回所有的属性集
249 
250 try {
251 NamingEnumeration answer = dc.search(searchBase, searchFilter,
252 searchCtls);
253 if (answer == null || answer.equals(null)) {
254 System.out.println("answer is null");
255 } else {
256 System.out.println("answer not null");
257 }
258 while (answer.hasMoreElements()) {
259 SearchResult sr = (SearchResult) answer.next();
260 System.out
261 .println("************************************************");
262 System.out.println("getname=" + sr.getName());
263 Attributes Attrs = sr.getAttributes();
264 if (Attrs != null) {
265 try {
266 
267 for (NamingEnumeration ne = Attrs.getAll(); ne
268 .hasMore();) {
269 Attribute Attr = (Attribute) ne.next();
270 System.out.println("AttributeID="
271 + Attr.getID().toString());
272 // 读取属性值
273 for (NamingEnumeration e = Attr.getAll(); e
274 .hasMore(); totalResults++) {
275 String user = e.next().toString(); // 接受循环遍历读取的userPrincipalName用户属性
276 System.out.println(user);
277 }
278 // System.out.println(" ---------------");
279 // // 读取属性值
280 // Enumeration values = Attr.getAll();
281 // if (values != null) { // 迭代
282 // while (values.hasMoreElements()) {
283 // System.out.println(" 2AttributeValues="
284 // + values.nextElement());
285 // }
286 // }
287 // System.out.println(" ---------------");
288 }
289 } catch (NamingException e) {
290 System.err.println("Throw Exception : " + e);
291 }
292 }
293 }
294 System.out.println("Number: " + totalResults);
295 } catch (Exception e) {
296 e.printStackTrace();
297 System.err.println("Throw Exception : " + e);
298 }
299 }
300 
301 /**
302 * 主函数用于测试
303 * 
304 * @param args
305 */
306 public static void main(String[] args) {
307 new LdapbyUser("CN=RyanHanson", "bbs.it-home.org");
308 }
309 }

发表回复