【LDAP】Spring项目同步LDAP域用户信息总览(含ldapTemplate.search仅查询1000条数据的解决方案)

【LDAP】Spring项目同步LDAP域用户信息总览(含ldapTemplate.search仅查询1000条数据的解决方案)

一、LDAP简介

  • 维基百科介绍:

轻量级目录访问协议( LDAP) 是一种开放的、供应商中立的行业标准应用协议,用于通过Internet 协议(IP) 网络访问和维护分布式目录信息服务。目录服务允许在整个网络中共享有关用户、系统、网络、服务和应用程序的信息,因此在开发Intranet和 Internet 应用程序中发挥着重要作用。例如,目录服务可以提供任何有组织的记录集,通常具有分层结构,例如公司电子邮件目录。类似地,电话簿也是具有地址和电话号码的用户列表。

LDAP广泛应用于组织中的身份管理、访问控制、电子邮件系统、单点登录等领域,提供了一种高效、灵活的方式来组织和检索分布式信息。

二、关于LDAP的一些关键概念

  • 目录服务(Directory Service): LDAP主要用于访问目录服务,而目录服务是一种层次结构化的数据库,用于存储和检索有关组织中各种实体(如用户、组、设备)的信息。

  • 层次结构(Hierarchy): LDAP目录数据以层次结构的形式组织,类似于文件系统的树状结构。每个目录项(entry)都有一个唯一的标识符(Distinguished Name,DN),表示在层次结构中的位置。

  • 条目(Entry): 目录中的每个实体都被称为一个条目。每个条目包含一组属性-值对,描述了实体的特征和属性。

  • 属性(Attribute): 属性是条目的特定信息,例如用户的姓名、电子邮件地址等。每个属性都有一个唯一的标识符(Attribute Type),对应着属性值。

  • LDAP协议: LDAP定义了一套客户端和服务器之间进行通信的规范,以实现对目录服务的操作。常见的LDAP操作包括搜索、添加、删除、修改等。

  • 端口: LDAP通常使用TCP协议,标准端口号是389。同时,LDAP也可以通过安全套接字层(SSL)进行加密通信,使用的端口号是636。

  • 认证: LDAP支持基于用户名和密码的身份验证,确保只有授权用户能够访问和修改目录信息。

三、LDAP用户信息案例

以下是一个简单的LDAP用户信息的例子:

  • Distinguished Name (DN): uid=johndoe,ou=people,dc=example,dc=com
    • 表示该用户在LDAP层次结构中的唯一标识符。
  • Attributes (属性):
    • ‘uid’: johndoe
      • 用户的唯一标识符,通常是用户名。
    • ‘cn’:John Doe
      • 用户的通用名称,即用户的全名。
    • ‘sn’: Doe
      • 用户的姓氏。
    • ‘givenName’: John
      • 用户的名字。
    • ‘mail’: johndoe@example.com
      • 用户的电子邮件地址。
    • ‘userPassword’: {SHA}5en6G6MezRroT3XKqkdPOmY/BfQ=
      • 用户的密码,通常以加密形式存储。

这是一个基本的LDAP用户信息示例,其中包含了用户的基本身份信息、电子邮件地址以及密码。这样的信息可以用于实现身份验证、访问控制等功能。在实际应用中,用户信息的属性和结构可能会根据组织的需求而有所不同。

四、Java同步LDAP用户信息到MySQL

1、引入Maven依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-ldap</artifactId>
</dependency>
2、LDAP认证信息配置

注:LDAP 389端口和3268的区别

LDAP(Lightweight Directory Access Protocol)通常使用两个不同的端口进行通信,分别是389和3268。它们之间的主要区别在于目标服务器和所执行的操作。

  1. LDAP端口 389:
    • 用途: 389端口是LDAP的标准端口,主要用于非安全的LDAP通信。
    • 目标服务器: 通常用于与单个LDAP服务器建立连接,执行标准的LDAP操作。
    • 操作类型: 适用于基本的LDAP查询、添加、修改、删除等操作。
    • 加密: 数据在传输过程中不加密,可能存在安全风险。
  2. LDAP端口 3268:
    • 用途: 3268端口也是LDAP端口,但用于LDAP全局编录服务。
    • 目标服务器: 用于在整个Active Directory森林中搜索(查询)用户信息。
    • 操作类型: 主要用于执行LDAP搜索操作,支持在多个域控制器之间进行全局搜索。
    • 加密: 支持加密通信,提供更安全的数据传输。

总结:

  • 使用389端口时,连接的是特定的LDAP服务器,适用于单个域或单个目录树。
  • 使用3268端口时,连接的是全局编录服务,适用于在整个Active Directory森林中进行全局搜索,跨越多个域。

由于当前案例为全局检索用户信息,故使用 3268 端口

  # ldap 连接信息ldap:urls: ldap://10.*.*.*:3268username: *********password: *********
3、用户实体

用于将检索到的用户信息映射为Java实例对象

import lombok.Data;@Data
public class LdapUser {/*** 唯一标识(code)*/private String code;/*** 用户名(account)*/private String account;/*** 昵称(name)*/private String name;/*** 真名(realName)*/private String realName;/*** 用户邮箱(email)*/private String email;/*** 手机号*/private String phone;}
4、同步功能代码
package org.springblade.modules.system.timing;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.cache.SysCache;
import org.springblade.common.constant.DictBizConstant;
import org.springblade.common.constant.TenantConstant;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tenant.BladeTenantProperties;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.DesUtil;
import org.springblade.core.tool.utils.DigestUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.system.entity.Tenant;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.ldap.entity.LdapUser;
import org.springblade.modules.system.service.impl.UserServiceImpl;
import org.springframework.ldap.control.PagedResultsDirContextProcessor;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.query.LdapQuery;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.naming.directory.SearchControls;
import java.util.ArrayList;
import java.util.List;import static org.springblade.common.constant.DictBizConstant.*;
import static org.springblade.core.cache.constant.CacheConstant.USER_CACHE;
import static org.springframework.ldap.query.LdapQueryBuilder.query;/*** LDAP用户信息同步定时任务*/
@Component
@AllArgsConstructor
@Slf4j
public class GotionUserTask {private final UserServiceImpl userService;private final LdapTemplate ldapTemplate;/*** 每日凌晨执行一次*/@Scheduled(cron = "0 0 0 * * ?")public void userSyncTask() {List<LdapUser> allLdapUsers = this.queryUsersPage();// 所有用户唯一值for (LdapUser ldapUser : allLdapUsers) {if (!"null".equals(ldapUser.getAccount()) && ldapUser.getAccount() != null){CacheUtil.clear(USER_CACHE);// 将 LdapUser 转换为 UserUser user = this.ldapUserToSystemUser(ldapUser);if (StringUtil.isBlank(user.getTenantId())) {user.setTenantId(BladeConstant.ADMIN_TENANT_ID);}Long userCount = userService.getBaseMapper().selectCount(Wrappers.<User>query().lambda().eq(User::getTenantId, user.getTenantId()).eq(User::getAccount, user.getAccount()));if (userCount > 0L && Func.isEmpty(user.getId())) {// 若当前用户已存在,则更新用户信息User oldUser = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getAccount, user.getAccount()));oldUser.setCode(ldapUser.getCode());oldUser.setName(ldapUser.getName());oldUser.setRealName(!"null".equals(ldapUser.getRealName()) ? ldapUser.getRealName() : null);oldUser.setEmail(!"null".equals(ldapUser.getEmail()) ? ldapUser.getEmail() : null);oldUser.setPhone(!"null".equals(ldapUser.getPhone()) ? ldapUser.getPhone() : null);userService.updateUser(oldUser);} else {userService.submit(user);}}}}/*** 分页查询LDAP中的所有的用户息** @return 结果*/public List<LdapUser> queryUsersPage() {List<LdapUser> list = new ArrayList<>();SearchControls searchControls = new SearchControls();/** 0:OBJECT_SCOPE,搜索指定的命名对象。* 1:ONE LEVEL_SCOPE,只搜索指定命名对象的一个级别,这是缺省值。* 2:SUBTREE_SCOPE,搜索以指定命名对象为根结点的整棵树*/searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);// 每次查询条数:默认1000条PagedResultsDirContextProcessor processor = new PagedResultsDirContextProcessor(1000);//返回的参数// 映射对象AttributesMapper<LdapUser> CN_ATTRIBUTES_MAPPER = attributes -> {LdapUser ldapUser = new LdapUser();ldapUser.setCode(String.valueOf(attributes.get("distinguishedName") != null ? attributes.get("distinguishedName").get() : null));ldapUser.setAccount(String.valueOf(attributes.get("sAMAccountName") != null ? attributes.get("sAMAccountName").get() : null));ldapUser.setName(String.valueOf(attributes.get("cn") != null ? attributes.get("cn").get() : null));ldapUser.setRealName(String.valueOf(attributes.get("name") != null ? attributes.get("name").get() : null));ldapUser.setEmail(String.valueOf(attributes.get("mail") != null ? attributes.get("mail").get() : null));ldapUser.setPhone(String.valueOf(attributes.get("telephoneNumber") != null ? attributes.get("telephoneNumber").get() : null));return ldapUser;};//查询条件LdapQuery queryPerson = query().base(DictBizConstant.GOTION_CODE_PUBLIC_SIGNS).where("objectClass").is("person");do {List<LdapUser> search = ldapTemplate.search(queryPerson.base(),queryPerson.filter().encode(),searchControls,CN_ATTRIBUTES_MAPPER,processor);list.addAll(search);} while (processor.hasMore());return list;}/**将映射的LDAP用户对象 转换为 当前系统的用户对象*/public User ldapUserToSystemUser(LdapUser ldapUser) {User user = new User();user.setCode(!"null".equals(ldapUser.getCode()) ? ldapUser.getCode() : null);user.setUserType(GOTION_DEF_USER_TYPE); // 默认用户类型user.setAccount(ldapUser.getAccount()); // 登录名称(用户在当前系统的登录名,应为)user.setPassword(GOTION_DEF_PWD); // 默认密码user.setName(ldapUser.getName());user.setRealName(!"null".equals(ldapUser.getRealName()) ? ldapUser.getRealName() : null);user.setAvatar(null);user.setEmail(!"null".equals(ldapUser.getEmail()) ? ldapUser.getEmail() : null);user.setPhone(!"null".equals(ldapUser.getPhone()) ? ldapUser.getPhone() : null);user.setSex(null);user.setRoleId(GOTION_DEF_ROLE); // 默认权限user.setDeptId(GOTION_DEF_DEPT); // 默认部门user.setPostId(GOTION_DEF_POST); // 默认岗位return user;}}
5、结果

LDAP中的用户信息:

image-20231201112455054

MySQL中的用户信息:

image-20231201112710818

Over!

加粗样式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/238160.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【趣味JavaScript】一文让你读懂JavaScript原型对象与原型链的继承,探秘属性的查找机制! 《重置版》

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起学习和进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&a…

geoserver 发布图层(tif、shp等)

我们用得最多的是这个板块的内容 下面我们来尝试发布地图。点击【数据】——【工作区】——【添加新的工作区】&#xff0c;工作区可以理解为是用来存放发布地图的一个集合。 在【新建工作区】中输入名称&#xff0c;还有一个命名空间URI&#xff0c;这个只要保持和之前的工作区…

【软件推荐】卸载360软件geek;护眼软件flux;

卸载360软件geek f.lux: software to make your life better (justgetflux.com) 卸载完扫描残留 护眼软件 hf.lux: software to make your life better (justgetflux.com)https://justgetflux.com/https://justgetflux.com/

python中的enumerate函数

enumerate函数是Python内置builtins模块中的一个函数&#xff0c;用于将一个可迭代对象转换为一个索引-元素对的枚举对象&#xff0c;从而方便地同时获得索引和元素&#xff0c;并在循环迭代中使用。 enumerate函数的语法格式为&#xff1a;enumerate(iterable, start0) itera…

春秋云境:CVE-2022-32991(sql注入)

靶标介绍&#xff1a; 该CMS的welcome.php中存在SQL注入攻击。 获取登录地址 http://eci-2zeb0096que0556y47vq.cloudeci1.ichunqiu.com:80 登录注册 注册成功登录进入注册接口 参数接口一 发现接口参数q http://eci-2zeb0096que0556y47vq.cloudeci1.ichunqiu.com/welcome.p…

疯狂英语李阳团队到中科国药•中科大有大健康产业上市企业孵化平台

11月21日&#xff0c;李阳导师团队一行莅临中科国药•中科大有大健康上市企业孵化平台深圳盐田孵化园区考察交流、合作洽谈。期间&#xff0c;李阳导师团队参观孵化园区企业及深圳盐田国际职业培训学院&#xff0c;了解国际职业培训学院的发展情况&#xff0c;对国际职业教育规…

小米摄像头拆机教程

今天拆解一下好久不用的小米摄像头&#xff0c;记录下拆机过程&#xff0c;有需要的小伙伴可以自行查看 一、拆底座 首先拿出底座的四个橡皮塞、把对应的螺丝拧下来就可以了&#xff0c;这一步还是比较简单的 二、拆下底部排线 三、拆下底部电机和底座 按下方的红圈拆掉电机上的…

iOS 开发高效率工具包:10 大必备工具

​ 作为 iOS 开发人员&#xff0c;拥有合适的工具可以极大地提高您的工作效率和工作质量。无论您是刚刚起步还是已经开发 iOS 应用程序多年&#xff0c;以下是每个 iOS 开发人员都应该了解的 10 大必备工具。 让我们开始 Xcode Xcode 是用于 iOS 开发的官方 IDE&#xff08;…

2023年12月02日新闻简报(国内国际)

新闻简报 每天三分钟&#xff0c;朝闻天下事。今天是&#xff1a;2023年12月02日&#xff0c;星期六&#xff0c;农历十月廿十&#xff0c;祝工作愉快&#xff0c;身体健康&#xff0c;生活喜乐&#xff1a;&#xff1a; 国内新闻 1、商务部&#xff1a;对原产于澳大利亚的进…

【编译警告】start value has mixed support, consider using flex-start instead

css规范问题&#xff0c;flex布局下&#xff0c;justify-content:start; 应该为&#xff1a;justify-content: flex-start

C++ 学习 之 类的初始化与逗号运算符的联动

我们来看一个代码 class A { public:A(int x) {cout << "123" << endl;}A(int x, int y) {cout << "456" << endl;}}a (1, 2); int main() {} 这个代码的输出结果是什么&#xff1f; 答案是 123 因为编译器把 ( 1 , 2 ) 识别…

基于springboot实现智慧党建系统项目【项目源码】计算机毕业设计

基于springboot实现智慧党建系统演示 Java技术 Java是由Sun公司推出的一门跨平台的面向对象的程序设计语言。因为Java 技术具有卓越的通用性、高效性、健壮的安全性和平台移植性的特点&#xff0c;而且Java是开源的&#xff0c;拥有全世界最大的开发者专业社群&#xff0c;所以…