将Ldap组织结构及用户信息同步到MySQL,用Spring Boot项目操作
从上一篇《将Mybatis引入Spring Boot项目连接数据库操作》知道了如何在Spring Boot项目操作数据库,学会了增删查改基本操作方法。本节记录如何从Ldap获取组织结构及用户信息并导入数据库。
一,引入Maven依赖并设置ldap连接信息
首先在pom.xml添加引入ldap依赖,如下所示:
<!-- LDAP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-ldap</artifactId>
</dependency>
保存后等待自动加载插件,加载完成后在application.properties配置文件中写目标ldap连接信息:
# 目标ldap地址
spring.ldap.urls=ldap://192.168.10.168:389
# base是Base DN 即根节点
spring.ldap.base=DC=ldap,DC=local
# 指定用户的username是User DN即distinguishedName,可分辨名称、标识名称
spring.ldap.username=CN=Administrator,CN=Users,DC=ldap,DC=local
# 指定用户的密码
spring.ldap.password=这里写密码
上面是示例。如果不确定信息是否正确,可以用LDAPSoft Ldap Browser,AdminLdap等客户端工具连接测试。能正确加载组织结构及用户信息代表连接信息正确。保存配置。
二,从ldap获取数据的基础方法,用户及部门实体模型
在项目中新建package包,为了容易区分取名“LdapDemo”,在里面新建3个Class类,分别取名LdapPerson,LdapDepartment,LdapService。前两个是ldap用户信息实体模型和ldap部门信息实体模型,第3个是写获取数据等基础方法的Service。
LdapPerson.java代码如下:
package xxh.springbootmvc.xxhdemo1.LdapDemo;
public class LdapPerson {
public String getObjectClass() {
return objectClass;
}
public void setObjectClass(String objectClass) {
this.objectClass = objectClass;
}
public String getCn() {
return cn;
}
public void setCn(String cn) {
this.cn = cn;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getsAMAccountName() {
return sAMAccountName;
}
public void setsAMAccountName(String sAMAccountName) {
this.sAMAccountName = sAMAccountName;
}
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public String getGivenName() {
return givenName;
}
public void setGivenName(String givenName) {
this.givenName = givenName;
}
public String getObjectGUID() {
return objectGUID;
}
public void setObjectGUID(String objectGUID) {
this.objectGUID = objectGUID;
}
public boolean isDeleted() {
return isDeleted;
}
public void setDeleted(boolean deleted) {
isDeleted = deleted;
}
public boolean isPrivilegeHolder() {
return isPrivilegeHolder;
}
public void setPrivilegeHolder(boolean privilegeHolder) {
isPrivilegeHolder = privilegeHolder;
}
public boolean isRecycled() {
return isRecycled;
}
public void setRecycled(boolean recycled) {
isRecycled = recycled;
}
public String getDistinguishedName() {
return distinguishedName;
}
public void setDistinguishedName(String distinguishedName) {
this.distinguishedName = distinguishedName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
private String objectClass; // organizationalPerson
private String cn; // 名称、唯一标识
private String displayName; // 显示名
private String sAMAccountName; // 登录名(唯一标识)
private String sn; // 姓
private String givenName; // 名
private String objectGUID;
private boolean isDeleted; // 删除的、禁用的
private boolean isPrivilegeHolder; // 特权
private boolean isRecycled; // 恢复的
private String distinguishedName; // DN
private String description;
}
保存。
LdapDepartment.java代码如下:
package xxh.springbootmvc.xxhdemo1.LdapDemo;
public class LdapDepartment {
public String getObjectClass() {
return objectClass;
}
public void setObjectClass(String objectClass) {
this.objectClass = objectClass;
}
public String getOu() {
return ou;
}
public void setOu(String ou) {
this.ou = ou;
}
public String getObjectGUID() {
return objectGUID;
}
public void setObjectGUID(String objectGUID) {
this.objectGUID = objectGUID;
}
public boolean isDeleted() {
return isDeleted;
}
public void setDeleted(boolean deleted) {
isDeleted = deleted;
}
public boolean isPrivilegeHolder() {
return isPrivilegeHolder;
}
public void setPrivilegeHolder(boolean privilegeHolder) {
isPrivilegeHolder = privilegeHolder;
}
public boolean isRecycled() {
return isRecycled;
}
public void setRecycled(boolean recycled) {
isRecycled = recycled;
}
public String getDistinguishedName() {
return distinguishedName;
}
public void setDistinguishedName(String distinguishedName) {
this.distinguishedName = distinguishedName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
private String objectClass; // organizationalUnit
private String ou; //名称、唯一标识
private String objectGUID;
private boolean isDeleted; // 删除的、禁用的
private boolean isPrivilegeHolder; // 特权
private boolean isRecycled; // 恢复的
private String distinguishedName; // DN
private String description;
}
LdapService.java代码如下:
package xxh.springbootmvc.xxhdemo1.LdapDemo; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.stereotype.Service;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import java.io.*;
import java.util.List; import static org.springframework.ldap.query.LdapQueryBuilder.query; @Service
public class LdapService {
@Autowired
private LdapTemplate ldapTemplate; // 获取Ldap部门
public List<LdapDepartment> getLdapDepartment(String objectClass,String DN) {
if (null == objectClass || objectClass.length() < 1)
objectClass = "organizationalUnit";
System.out.println("getLdapDepartment> " + objectClass + "," + DN);
ldapTemplate.setIgnorePartialResultException(true);
return ldapTemplate.search(
query().where("objectclass").is(objectClass)
.and("distinguishedName").like(DN),
new LdapDepartmentAttributesMapper()); }
// 自定义序列化Ldap部门实体
private class LdapDepartmentAttributesMapper implements AttributesMapper<LdapDepartment> {
@Override
public LdapDepartment mapFromAttributes(Attributes attrs) throws NamingException {
LdapDepartment ldapDepartment = new LdapDepartment();
if (null != attrs.get("objectClass")) {
ldapDepartment.setObjectClass((String) attrs.get("objectClass").get());
}
if (null != attrs.get("ou")) {
ldapDepartment.setOu((String) attrs.get("ou").get());
}
if (null != attrs.get("objectGUID")) {
// 将ldap的objectGUID转换成字符串
ldapDepartment.setObjectGUID(convertObjectGUID(attrs.get("objectGUID").get()));
} if (null != attrs.get("isDeleted")) {
ldapDepartment.setDeleted((boolean) attrs.get("isDeleted").get());
}
if (null != attrs.get("isPrivilegeHolder")) {
ldapDepartment.setPrivilegeHolder((boolean) attrs.get("isPrivilegeHolder").get());
}
if (null != attrs.get("isRecycled")) {
ldapDepartment.setRecycled((boolean) attrs.get("isRecycled").get());
} if (null != attrs.get("distinguishedName")) {
ldapDepartment.setDistinguishedName((String) attrs.get("distinguishedName").get());
}
if (null != attrs.get("description")) {
ldapDepartment.setDescription((String) attrs.get("description").get());
} return ldapDepartment;
}
} // 获取Ldap用户
public List<LdapPerson> getLdapPerson(String objectClass,String DN) {
if(null==objectClass || objectClass.length()<1)
objectClass="organizationalPerson"; ldapTemplate.setIgnorePartialResultException(true);
return ldapTemplate.search(
query().where("objectclass").is(objectClass)
.and("distinguishedName").is(DN),
new LdapPersonAttributesMapper());
}
// 自定义序列化Ldap用户实体
private class LdapPersonAttributesMapper implements AttributesMapper<LdapPerson> {
@Override
public LdapPerson mapFromAttributes(Attributes attrs) throws NamingException {
LdapPerson ldapPerson = new LdapPerson();
if (null != attrs.get("objectClass")) {
ldapPerson.setObjectClass((String) attrs.get("objectClass").get());
}
if (null != attrs.get("cn")) {
ldapPerson.setCn((String) attrs.get("cn").get());
}
if (null != attrs.get("displayName")) {
ldapPerson.setDisplayName((String) attrs.get("displayName").get());
}
if (null != attrs.get("sAMAccountName")) {
ldapPerson.setsAMAccountName((String) attrs.get("sAMAccountName").get());
}
if (null != attrs.get("sn")) {
ldapPerson.setSn((String) attrs.get("sn").get());
}
if (null != attrs.get("givenName")) {
ldapPerson.setGivenName((String) attrs.get("givenName").get());
}
if (null != attrs.get("objectGUID")) {
// 将ldap的objectGUID转换成字符串
ldapPerson.setObjectGUID(convertObjectGUID(attrs.get("objectGUID").get()));
} if (null != attrs.get("isDeleted")) {
ldapPerson.setDeleted((boolean) attrs.get("isDeleted").get());
}
if (null != attrs.get("isPrivilegeHolder")) {
ldapPerson.setPrivilegeHolder((boolean) attrs.get("isPrivilegeHolder").get());
}
if (null != attrs.get("isRecycled")) {
ldapPerson.setRecycled((boolean) attrs.get("isRecycled").get());
} if (null != attrs.get("distinguishedName")) {
ldapPerson.setDistinguishedName((String) attrs.get("distinguishedName").get());
}
if (null != attrs.get("description")) {
ldapPerson.setDescription((String) attrs.get("description").get());
} return ldapPerson;
}
} // 示例:获取全部用户名
public List<String> getAllPersonNames() {
ldapTemplate.setIgnorePartialResultException(true);
return ldapTemplate.search(
query().where("objectclass").is("person"), (AttributesMapper<String>) attrs -> (String) attrs.get("cn").get());
} //region 这里都是解决ldap获取数据中的objectGUID乱码问题,虽然解决了乱码但是值不一样,该值不建议当做标识使用。
/**
* 对象转数组
* @param obj
* @return
*/
private static byte[] toByteArray (Object obj) {
byte[] bytes = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
bytes = bos.toByteArray ();
oos.close();
bos.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return bytes;
} /**
* 数组转对象
* @param bytes
* @return
*/
private static Object toObject (byte[] bytes) {
Object obj = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream (bytes);
ObjectInputStream ois = new ObjectInputStream (bis);
obj = ois.readObject();
ois.close();
bis.close();
} catch (IOException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
return obj;
} private static String AddLeadingZero(int k) {
return (k <= 0xF) ? "0" + Integer.toHexString(k) : Integer.toHexString(k);
}
private static String convertObjectGUID(Object ObjectGUID) {
byte[] GUID = toByteArray(ObjectGUID); String strGUID = "";
String byteGUID = ""; //Convert the GUID into string using the byte format
for (int c = 0; c < GUID.length; c++) {
byteGUID = byteGUID + "\\" + AddLeadingZero((int) GUID[c] & 0xFF);
}
// strGUID = "{";
strGUID = strGUID + AddLeadingZero((int) GUID[3] & 0xFF);
strGUID = strGUID + AddLeadingZero((int) GUID[2] & 0xFF);
strGUID = strGUID + AddLeadingZero((int) GUID[1] & 0xFF);
strGUID = strGUID + AddLeadingZero((int) GUID[0] & 0xFF);
strGUID = strGUID + "-";
strGUID = strGUID + AddLeadingZero((int) GUID[5] & 0xFF);
strGUID = strGUID + AddLeadingZero((int) GUID[4] & 0xFF);
strGUID = strGUID + "-";
strGUID = strGUID + AddLeadingZero((int) GUID[7] & 0xFF);
strGUID = strGUID + AddLeadingZero((int) GUID[6] & 0xFF);
strGUID = strGUID + "-";
strGUID = strGUID + AddLeadingZero((int) GUID[8] & 0xFF);
strGUID = strGUID + AddLeadingZero((int) GUID[9] & 0xFF);
strGUID = strGUID + "-";
strGUID = strGUID + AddLeadingZero((int) GUID[10] & 0xFF);
strGUID = strGUID + AddLeadingZero((int) GUID[11] & 0xFF);
strGUID = strGUID + AddLeadingZero((int) GUID[12] & 0xFF);
strGUID = strGUID + AddLeadingZero((int) GUID[13] & 0xFF);
strGUID = strGUID + AddLeadingZero((int) GUID[14] & 0xFF);
strGUID = strGUID + AddLeadingZero((int) GUID[15] & 0xFF);
// strGUID = strGUID + "}"; // System.out.println("GUID (String format): " + strGUID);
// System.out.println("GUID (Byte format): " + byteGUID);
return strGUID;
}
//endregion }
Service里面方法实现可以参考下面几篇博客:
https://www.jianshu.com/p/77517e26a357
https://blog.csdn.net/a118170653/article/details/43449331
注意:
1,LdapService类前面要加@Service标注。
2,需要在类体声明LdapTemplate才能在方法里使用(在方法里面声明不行)。
@Autowired
private LdapTemplate ldapTemplate;
3,查询ldap组织结构及用户信息需要使用拉姆达表达式,具体请看上面代码示例。
三,调用LdapService获取数据并以接口形式输出显示
在项目里面创建Class类,命名为ldapTestController,在这里面写接口调用LdapService获取数据并以接口形式输出显示。如下:
package xxh.springbootmvc.xxhdemo1.LdapDemo; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
@EnableAutoConfiguration
@RequestMapping("/v1/ldapdemo")
public class ldapTestController {
/* 声明LdapService */
@Autowired
private LdapService ldapService; // http://localhost:8888/v1/ldapdemo/getPersonNameList
/* 获取所有用户名称接口 */
@RequestMapping("/getPersonNameList")
public Object queryPersonNameList() {
return ldapService.getAllPersonNames();
} // http://localhost:8888/v1/ldapdemo/getLdapDepartmentList?objectclass=&dn=
// http://localhost:8888/v1/ldapdemo/getLdapDepartmentList?objectclass=&dn=
// http://localhost:8888/v1/ldapdemo/getLdapDepartmentList?dn=OU=%E8%BF%90%E8%90%A5%E6%9C%8D%E5%8A%A1%E9%83%A8,DC=ldap,DC=local
/* 根据筛选获条件取部门接口 */
@RequestMapping("/getLdapDepartmentList")
public Object queryLdapDepartmentList(String objectclass, String dn) {
if (null == dn || dn.length() < 1)
dn = "OU=实施组,OU=运营服务部,DC=ldap,DC=local"; return ldapService.getLdapDepartment(objectclass, dn);
} // http://localhost:8888/v1/ldapdemo/getLdapPersonList?dn=OU=实施组,OU=运营服务部,DC=ldap,DC=local
/* 根据筛选获条件取用户接口 */
@RequestMapping("/getLdapPersonList")
public Object queryLdapPersonList(String objectclass, String dn) {
if (null == dn || dn.length() < 1)
dn = "CN=刘备,OU=实施组,OU=运营服务部,DC=ldap,DC=local"; return ldapService.getLdapPerson(objectclass, dn);
} }
我这里是直接用接口显示出来。其实真实项目中是录入到数据库里面。
本篇博客涉及到的项目文件及目录结构:

四,接口效果截图
获取所有用户名称接口 效果如下:

根据筛选获条件取部门接口 效果如下:

根据筛选获条件取用户接口 效果如下:

本篇总结就写到这里了。
缺点:
1,虽然将Ldap的objectGUID能转换成字符串不再是乱码,但是值不等于Ldap里面的objectGUID值。所以不建议用它作为数据对比的标识。
2,本篇代码还不能按照友好的上下级关系一层一层往下查找(目前是查出所有的部门或用户,或者筛选已知部门或已知用户)。
上一篇:将Mybatis引入Spring Boot项目连接数据库操作
下一篇:
将Ldap组织结构及用户信息同步到MySQL,用Spring Boot项目操作的更多相关文章
- Spring Boot教程(四十二)LDAP来管理用户信息(2)
使用spring-data-ldap的基础用法,定义LDAP中属性与我们Java中定义实体的关系映射以及对应的Repository @Data @Entry(base = "ou=peopl ...
- Spring Boot教程(四十一)LDAP来管理用户信息(1)
LDAP简介 LDAP(轻量级目录访问协议,Lightweight Directory Access Protocol)是实现提供被称为目录服务的信息服务.目录服务是一种特殊的数据库系统,其专门针对读 ...
- sharepoint用户信息同步出错
首先使用工具定位问题,然后权限不够授予权限 C:\Program Files\Microsoft Office Servers\15.0\Synchronization Service\UIShell
- 解决idea spring boot项目中target中没有同步更新最新目录文件及资源
idea不像eclipse那样自动将新保存的文件或目录及其他资源更新到target目录中,必须在pom.xml中设置 <build> <resources> <resou ...
- 利用 Scrapy 爬取知乎用户信息
思路:通过获取知乎某个大V的关注列表和被关注列表,查看该大V和其关注用户和被关注用户的详细信息,然后通过层层递归调用,实现获取关注用户和被关注用户的关注列表和被关注列表,最终实现获取大量用户信息. 一 ...
- spring oauth2获取当前登录用户信息。
使用spring oauth2框架做授权鉴定.想获取当前用户信息怎么办? 我们知道spring oauth2是基于spring security的实现的. spring security可以通过Sec ...
- Spring Boot实现学生信息增删改查
上一篇博客写了如何初始化一个简单的Spring Boot项目,这次详细记录一下如何连接数据库并实现增删改查基本操作. 我使用的是MySQL 5.5+Navicat,MySQL量级比较轻,当然微软的SQ ...
- Elasticsearch的快速使用——Spring Boot使用Elastcisearch, 并且使用Logstash同步mysql和Elasticsearch的数据
我主要是给出一些方向,很多地方没有详细说明.当时我学习的时候一直不知道怎么着手,花时间找入口点上比较多,你们可以直接顺着方向去找资源学习. 如果不是Spring Boot项目,那么根据Elastics ...
- Spring Boot(IDEA,Gradle)超详细用户管理项目(一)——Hello World
1.构建工具的配置(Gradle):自定义-所有设置:构建.执行.部署-构建工具-Gradle: 设置Gradle用户主目录:(该目录相当于仓库,gradle将下载所需依赖到此目录下),此目录下可新建 ...
- Spring Boot中使用Actuator的/info端点输出Git版本信息
对于Spring Boot的Actuator模块相信大家已经不陌生了,尤其对于其中的/health./metrics等强大端点已经不陌生(如您还不了解Actuator模块,建议先阅读<Sprin ...
随机推荐
- 【VMware VCF】通过备份的配置文件还原 SDDC Manager 组件。
之前在这篇文章(使用 SFTP 服务器备份 VCF 核心组件的配置文件.)中配置并备份了 VCF 环境中 SDDC Manager 组件的配置文件,这篇文章接着这个主题,看看当 SDDC Manage ...
- 很干,但实用——4G模组供电设计及其选型推荐
4G模组的外部电源供电设计十分重要,对系统稳定.射频性能都有直接影响. 怎么让工程师朋友们在应用开发中少走弯路呢? 我将以Air780E为例,陆续分享系列实用干货.无论你是专家还是菜鸟,无论你是否 ...
- 【踩坑日记】uni-app相机抽帧,相机被多次初始化问题
缘起:最近频繁接到使用我们AI运行识别插件用户的反馈,部分机型在uni中抽几帧后,就不再帧的了.开始以为又是小程序的API兼容的问题(确有机型出现过抽帧兼容性问题),后面越来越多的反馈在原生下无问题, ...
- golang模板库之fasttemplate
简介 fasttemplate是一个比较简单.易用的小型模板库.fasttemplate的作者valyala另外还开源了不少优秀的库,如大名鼎鼎的fasthttp,前面介绍的bytebufferpoo ...
- golang定时器之timer+ticker
转载: https://juejin.cn/post/7327157426298011663 Timer 是一个一次性的定时器,用于在未来的某一时刻执行一次操作. 基本使用 创建 Timer 定时器的 ...
- kali 安装 shodan
声明! 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无 ...
- python雪花算法
雪花算法(Snowflake Algorithm)是一种用于生成唯一的ID的算法,它由Twitter开发.其生成的ID在全局范围内是唯一的,适合高并发场景.雪花算法生成的ID通常是一个64位的整数,包 ...
- Reverse the Rivers 题解
原题链接https://codeforces.com/problemset/problem/2036/E (暂时不会弄翻译,所以不上原题了) 说一下我对题意的理解吧 有n个国家,每个国家有k个区域,用 ...
- openEuler欧拉系统重置root密码
步骤: 系统启动时,出现如下页面,按e进入内核编辑模式 进入如下页面 按下光标后,找到linux开头这一行,修改ro为rw,并在行尾添加init=/bin/sh,修改后效果如下,在crtl+x保存后开 ...
- 【Amadeus原创】k8s添加新master或node
Master 1,在master上生成新的token [root@it-1c2d ]# kubeadm token create --print-join-command kubeadm join k ...