本文介绍: 一问读懂Ldap

LADP概述

LDAP(轻量目录访问协议)是一种用于访问和维护分布式目录信息服务协议目录服务是一种存储检索信息服务,通常用于存储组织内的用户信息组织结构网络设备数据。LDAP是一种轻量级协议设计用于目录中进行查找修改操作,而不是用于传输大量的数据

以下是LDAP的一些基本概念

目录服务(Directory Service): 目录服务是一种专门设计用于存储检索信息服务。与传统数据库不同,目录服务更注重提供高效的读取操作支持快速数据检索。LDAP是一种协议用于目录服务进行通信

目录(Directory): 目录是一种组织结构化数据方式,通常包含多个条目(Entry)。每个条目包含一组属性值,用于描述特定实体(如用户组织单位设备等)的信息

条目(Entry): 条目是目录中的基本单位,类似于数据库中的一行记录每个条目都有一个唯一标识符,称为DN(Distinguished Name)。

属性(Attribute): 属性是条目中存储的信息的命名和值对。例如,一个用户条目可能包含属性如姓名、电子邮件地址、电话号码等。

DN(Distinguished Name): DN是每个条目在目录中的唯一标识符,由一系列与目录结构相关名称组成。DN通常是一个层次结构例如cn=john,ou=users,dc=example,dc=com“。

LDAP协议: LDAP定义客户端和目录服务器之间进行通信规则。它使用TCP/IP协议栈,通常在389端口运行。LDAP协议支持多种操作,包括搜索添加删除修改等,以便对目录中的数据进行操作。

LDAP被广泛用于企业组织中,用于集中管理用户组织结构设备等信息。它是许多身份验证访问控制系统的基础,如单点登录(SSO)系统

步骤一:配置LDAP连接属性

application.propertiesapplication.yml文件添加LDAP连接属性例如LDAP服务器URL、用户名密码等。

步骤二:创建LDAP配置类:

创建一个@Configuration类,并使用@EnableWebSecurity注解启用Web安全性配置。在配置类中可以使用LDAP的相关配置属性来配置LDAP连接认证提供者。

步骤三:创建LDAP认证提供者:

实现UserDetailsService接口重写其中的loadUserByUsername()方法,要在Spring Boot项目整合LDAP(轻量级目录访问协议),可以使用Spring LDAP模块。以下是一个简单示例展示如何在Spring Boot中整合LDAP,并提供一些常见的操作示例

整合步骤

1.引入POM依赖

<dependency&gt;
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-ldap</artifactId>
</dependency>

2.在application.propertiesapplication.yml文件中提供LDAP连接的配置信息

ldap.url=ldap://your-ldap-server:389
ldap.base=dc=example,dc=com
ldap.userDnPattern=uid={0},ou=people
ldap.userSearchBase=ou=people

3.创建LdapDemoConfig

package com.example.springbootidapdemo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;

@Configuration
public class LdapDemoConfig {
    @Bean
    public LdapTemplate ldapTemplate() {
        LdapContextSource contextSource = new LdapContextSource();
        contextSource.setUrl("ldap://localhost:389");
        contextSource.setBase("dc=example,dc=com");
        contextSource.setUserDn("cn=admin,dc=example,dc=com");
        contextSource.setPassword("adminpassword");
        contextSource.afterPropertiesSet();

        LdapTemplate ldapTemplate = new LdapTemplate(contextSource);
        ldapTemplate.setIgnorePartialResultException(true);
        ldapTemplate.setDefaultTimeLimit(1000);
        ldapTemplate.setDefaultCountLimit(100);

        return ldapTemplate;
    }
}

4.方法概述对应Demo

前提需要提供基础DN、过滤器搜索控件和属性映射器。实际使用时,需要根据LDAP目录的结构和属性进行相应的配置。

1.ldapTemplate.find(根据指定搜索条件在LDAP目录中查找条目并返回结果)

public <T> T find(
        String dn,
        String filter,
        SearchControls controls,
        AttributesMapper<T> mapper)

dn: 搜索的基础DN(Distinguished Name),表示搜索的起始位置
filter: LDAP搜索过滤器定义匹配的条目的条件。
controls: 搜索控件,用于配置搜索的一些参数例如搜索范围返回的属性等。
mapper: 用于将搜索结果映射对象的 AttributesMapper

方法执行LDAP搜索并返回满足条件的第一个条目。如果没有匹配的条目,返回 null

Demo如下

@Service
public class LdapService {

    @Autowired
    private LdapTemplate ldapTemplate;

    public User findUser(String username) {
        String baseDn = "ou=people,dc=example,dc=com";
        String filter = "(uid=" + username + ")";
        
        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        return ldapTemplate.find(baseDn, filter, controls, new UserAttributesMapper());
    }

    private static class UserAttributesMapper implements AttributesMapper<User> {
        @Override
        public User mapFromAttributes(Attributes attributes) throws NamingException {
            return new User(/* user properties */);
        }
    }
}

下述demo展示关键代码块、重复描述不再过多赘述

2.ldapTemplate.findAll(根据指定的搜索条件在LDAP目录中查找多个条目并返回结果列表

public <T> List<T> findAll(
        String base,
        String filter,
        SearchControls controls,
        AttributesMapper<T> mapper)

base: 搜索的基础DN(Distinguished Name),表示搜索的起始位置

方法执行LDAP搜索并返回满足条件的所有条目的列表。如果没有匹配的条目,返回空列表

Demo如下

public List<User> findAllUsers() {
        String baseDn = "ou=people,dc=example,dc=com";
        String filter = "(objectClass=person)"; 
        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        return ldapTemplate.findAll(baseDn, filter, controls, new UserAttributesMapper());
    }

3.ldapTemplate.findOne(根据指定的搜索条件在LDAP目录中查找单个条目并返回结果

注意:如果没有匹配的条目,抛出 javax.naming.NameNotFoundException 异常。如果有匹配多个条目,抛出 javax.naming.NamingException 异常

public <T> T findOne(
        String dn,
        String filter,
        AttributesMapper<T> mapper)

Demo如下

public User findUser(String username) {
        String baseDn = "ou=people,dc=example,dc=com";
        String filter = "(uid=" + username + ")";
        return ldapTemplate.findOne(baseDn, filter, new UserAttributesMapper());
    }

4.ldapTemplate.findByDn(根据给定的DN(Distinguished Name)查找单个条目并返回结果

public <T> T findByDn(String dn, AttributesMapper<T> mapper)

方法会执行LDAP搜索并返回指定DN的条目,如果没有找到匹配的条目,返回 null

Demo如下

 public User findUserByDn(String userDn) {
        return ldapTemplate.findByDn(userDn, new UserAttributesMapper());
    }

5.ldapTemplate.findForStream(用于从 LDAP 目录中以流的方式获取多个条目的结果

public <T> Stream<T> findForStream(
        String base,
        String filter,
        SearchControls controls,
        AttributesMapper<T> mapper)

ldapTemplate.findForStream 方法会执行LDAP搜索并返回一个流(Stream),其中包含满足条件的所有条目的结果通过使用流的方式可以更高效地处理大量的搜索结果,而不必一次性将所有结果加载内存中。

Demo如下

public List<User> findAllUsers() {
        String baseDn = "ou=people,dc=example,dc=com";
        String filter = "(objectClass=person)";
        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        Stream<User> userStream = ldapTemplate.findForStream(baseDn, filter, controls, new UserAttributesMapper());
        return userStream.collect(Collectors.toList());
    }

注意:ldapTemplate.findForStream 方法是从 Spring LDAP 2.2 版本开始引入的。确保使用的是兼容的 Spring LDAP 版本。如果版本较旧,可能需要升级兼容版本或者使用其他方法处理 LDAP 搜索结果流

6.ldapTemplate.search(用于执行灵活的LDAP搜索并返回结果)

public <T> List<T> search(
        String base,
        String filter,
        SearchControls controls,
        AttributesMapper<T> mapper)

与之前介绍ldapTemplate.findAll 方法相似,ldapTemplate.search 方法也执行LDAP搜索,但它提供更多的灵活性,可以更精确地配置搜索参数。该方法返回满足条件的所有条目的列表

Demo如下

public List<User> searchUsers(String filter) {
        String baseDn = "ou=people,dc=example,dc=com";
        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        return ldapTemplate.search(baseDn, filter, controls, new UserAttributesMapper());
    }

7.ldapTemplate.searchForContext(用于执行LDAP搜索并返回搜索结果的上下文(DirContext))

public DirContext searchForContext(
        String base,
        String filter,
        SearchControls controls)

与之前介绍ldapTemplate.search 方法相比ldapTemplate.searchForContext 返回的是搜索结果的上下文,而不是直接返回映射后的对象列表。这样的设计使得可以更灵活地处理搜索结果,包括对搜索结果的进一步处理、解析和操作。

Demo如下:

public DirContext searchForContext(String filter) {
        String baseDn = "ou=people,dc=example,dc=com";
        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        return ldapTemplate.searchForContext(baseDn, filter, controls);
    }

8.ldapTemplate.searchForObject(用于执行LDAP搜索并返回单个对象作为结果)

public <T> T searchForObject(
        String base,
        String filter,
        SearchControls controls,
        Class<T> requiredType)

requiredType: 期望的返回类型

该方法执行LDAP搜索并返回单个对象,而不是返回一个对象列表。这可以方便地用于查找特定条件下的唯一条目。

Demo如下:

public User searchForUser(String username) {
        String baseDn = "ou=people,dc=example,dc=com";
        String filter = "(uid=" + username + ")";
        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        return ldapTemplate.searchForObject(baseDn, filter, controls, User.class);
    }

注意:如果没有找到匹配的条目,ldapTemplate.searchForObject 方法将返回 null

9.ldapTemplate.searchForStream(用于执行LDAP搜索并返回结果的流(Stream))

public <T> Stream<T> searchForStream(
        String base,
        String filter,
        SearchControls controls,
        Class<T> requiredType)

该方法执行LDAP搜索并返回一个流(Stream),其中包含满足条件的所有条目的结果。通过使用流的方式,可以更高效地处理大量的搜索结果,而不必一次性将所有结果加载到内存中。

Demo如下:

public List<User> searchForUsers(String filter) {
        String baseDn = "ou=people,dc=example,dc=com";
        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        Stream<User> userStream = ldapTemplate.searchForStream(baseDn, filter, controls, User.class);
        return userStream.collect(Collectors.toList());
    }

10.ldapTemplate.rebind(用于重新绑定更新)LDAP目录中的条目)

public void rebind(String dn, Object obj, Attributes attributes)

obj: 要重新绑定对象

该方法会将指定对象和属性重新绑定到LDAP目录中的指定DN。如果指定的DN不存在,则会创建新的条目。如果已存在具有相同DN的条目,则会更新现有条目的属性。

 public void updateUserInfo(String userDn, User newUser) {
        // Assume User class has appropriate getters and setters for user attributes
        Attributes attributes = // create or update attributes based on newUser

        ldapTemplate.rebind(userDn, newUser, attributes);
    }

注意:具体的 Attributes 对象的创建更新需要根据您的数据模型需求进行调整

11.ldapTemplate.rename(用于重命名移动)LDAP目录中的条目)

public void rename(String oldDn, String newDn)

oldDn: 要重命名的旧DN,表示LDAP目录中的一个条目。
newDn: 新的DN,表示条目在LDAP目录中的新位置

该方法会将指定的条目从旧的DN移动到新的DN,实现重命名效果

Demo如下:

public void renameUser(String oldDn, String newDn) {
        ldapTemplate.rename(oldDn, newDn);
    }

注意:新的DN必须包含新的父级DN,以确保条目被正确移动到新的位置例如,如果要将用户"ou=people,dc=example,dc=com" 移动"ou=otherPeople,dc=example,dc=com",则新的DN应为"uid=john,ou=otherPeople,dc=example,dc=com"

12.ldapTemplate.modifyAttributes(用于修改LDAP目录中条目的属性值)

public void modifyAttributes(String dn, ModificationItem[] mods)

mods: 要应用的修改项数组,表示要对条目进行的修改操作。

修改项(ModificationItem)由两个属性组成:修改操作类型DirContext.ADD_ATTRIBUTE、DirContext.REMOVE_ATTRIBUTEDirContext.REPLACE_ATTRIBUTE)和要修改的属性(Attribute)。

Demo如下:

public void updateUserPassword(String userDn, String newPassword) {
        ModificationItem[] mods = new ModificationItem[1];
        Attribute attribute = new BasicAttribute("userPassword", newPassword);
        mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attribute);
        ldapTemplate.modifyAttributes(userDn, mods);
    }

上述示例中,updateUserPassword 方法使用了 ldapTemplate.modifyAttributes 来根据用户DN(userDn)修改用户密码。首先,创建一个 ModificationItem 数组包含要进行的修改操作。在这个示例中,它只包含一项:用新密码替换(DirContext.REPLACE_ATTRIBUTE)userPassword 属性。然后,将这个修改项数组传递给 ldapTemplate.modifyAttributes 方法,以便进行修改

13.ldapTemplate.authenticate(用于对LDAP进行认证操作)

public boolean authenticate(String base, String filter, String password)

password: 用户密码,用于认证操作。

该方法用于验证给定用户密码是否与LDAP中指定条件的用户匹配。如果匹配成功,则返回 true,否则返回 false

Demo如下:

public boolean authenticateUser(String username, String password) {
        String baseDn = "ou=people,dc=example,dc=com";
        String filter = "(uid=" + username + ")";
        return ldapTemplate.authenticate(baseDn, filter, password);
    }

上述示例中,authenticateUser 方法使用了 ldapTemplate.authenticate验证用户的身份。需要提供基础DN、过滤器和用户密码。该方法将验证提供的用户名密码是否匹配LDAP中指定条件的用户,如果匹配成功,则返回 true,表示认证通过。

原文地址:https://blog.csdn.net/weixin_45735355/article/details/134396477

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_21674.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注