Spring Ldap

Spring Ldap是一个简化LDAP操作的框架,提供了类似Hibernate ORM的ODM技术,用于将对象映射到AD域。通过LdapContextSource和LdapTemplate进行操作,并支持ODM注解如@Entry、@Attribute、@Id。本文重点介绍了如何使用ODM映射组织单位和用户,以及如何配置和使用Repository进行AD域的数据交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring Ldap

  • Spring Ldap是一个用来简化LDAP操作的开源框架
  • Spring Ldap中的ODM技术可以像Hibernate的ORM一样将对象映射到AD域上
  • 该框架通过提供和ORM中相似的机制对LDAP相关操作进行封装,主要包括:
    • 类比SessionFactory的LdapContextSource
    • 类比HibernateTemplate等的LdapTemplate
    • 伪事务支持,能否与tx框架的TransactionManager混用未知
    • 类比JPA的使用@Entry、@Attribute、@Id标注的ODM——Object Directory Mapping
  • 本文的目的是通过Ldap操作获取AD域的组和用户
  • 文档:http://docs.spring.io/spring-ldap/docs/2.0.4.RELEASE/reference/

本文主要使用ODM技术映射对象,简化ObjectMapping操作,当然也可以不定义对象自己定义AttributesMapper,相关内容可以查看官方文档。

ORM映射

1.映射组织单位organizationalUnit

@Entry(objectClasses = { "organizationalUnit", "top" })
public final class Group {
    @Id
    @JsonIgnore // Name无法完全被转换成json字符串,所以不要转换
    private Name dn;

    @Attribute(name = "ou")
    private String groupName;

    @Attribute(name = "description")
    private String description;

    // getter setter tostring...
}

2.映射用户

@Entry(objectClasses = { "organizationalPerson", "person", "top", "user" })
public class Person {
    @Id
    @JsonIgnore
    private Name dn;

    @Attribute(name = "cn")
    private String fullName;

    @Attribute(name = "sn")
    private String lastName;

    @Attribute(name = "mail")
    private String mail;

    @Attribute(name = "managedObjects")
    private String managerObject;

    @Transient
    private String group;

    @Attribute(name = "description")
    private String description;

    // getter setter tostring...
}

关于ODM的解释:
- @Entry定义一个Entry对象,映射AD域的对象信息, objectClasses 指定对象类属性,是一个数组
- @Id 类似于ORM中的@Id,但是在这里是指DN值(在AD域中DN值是唯一的)
- @Attribute指定Entry中的某一个属性值,没有指定@Attribute的属性为改属性名
- @Transient表示该属性不映射AD域中的某个属性
- @DnAttribute(value=”ou”, index = 1) 表示将DN值中的某一个值取出作为该变量值

下面定义一个Repository访问AD域信息:

@Component
public class CustomLdapRepositoryImpl implements CustomLdapRepository {

    private LdapTemplate ldapTemplate;

    // open a ldap connection
    private void openLdapConnection(LdapGroupServerInfo serverInfo) {
        String url = "LDAP://" + serverInfo.getIp() + ":"
                + serverInfo.getPort();
        LdapContextSource contextSource = new LdapContextSource();
        contextSource.setUrl(url);
        contextSource.setUserDn(serverInfo.getDnName());
        contextSource.setPassword(new String(Base64.decode(serverInfo
                .getPassword().getBytes())));
        contextSource.setReferral("follow");
        contextSource.afterPropertiesSet();
        ldapTemplate = new LdapTemplate(contextSource);
        ldapTemplate.setIgnorePartialResultException(true);
    }

    @Override
    public List<Group> findGroupsByBase(LdapGroupServerInfo serverInfo,
            String base, int searchScope) {
        openLdapConnection(serverInfo);

        SearchControls searchControls = new SearchControls();
        searchControls.setSearchScope(searchScope);

        LdapName ldapName = null;
        try {
            ldapName = new LdapName(base);
        } catch (InvalidNameException e) {
            e.printStackTrace();
        }

        return ldapTemplate.findAll(ldapName, searchControls, Group.class);
    }

    @Override
    public List<Person> findPersonsByBase(LdapGroupServerInfo serverInfo,
            String base, int searchScope) {
        openLdapConnection(serverInfo);
        SearchControls searchControls = new SearchControls();
        searchControls.setSearchScope(searchScope);
        LdapName name = null;
        try {
            name = new LdapName(base);
        } catch (InvalidNameException e) {
            e.printStackTrace();
        }
        return ldapTemplate.findAll(name, searchControls, Person.class);
    }

    @Override
    public List<Person> findPersonsByEmail(LdapGroupServerInfo serverInfo,
            String base, String email) {
        openLdapConnection(serverInfo);
        // if no detail base attr, use server base to find
        if (base == null) {
            base = serverInfo.getBase();
        }

        SearchControls searchControls = new SearchControls();
        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        LdapName name = null;
        try {
            name = new LdapName(base);
        } catch (InvalidNameException e) {
            e.printStackTrace();
        }

        AndFilter filter = new AndFilter();
        filter.and(new EqualsFilter("mail", email));

        return ldapTemplate.find(name, filter, searchControls, Person.class);
    }

    @Override
    public List<Person> findManagersByPersonDN(LdapGroupServerInfo serverInfo,
            String personDN) {
        openLdapConnection(serverInfo);

        personDN = personDN.substring(personDN.indexOf(",") + 1);

        SearchControls searchControls = new SearchControls();
        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        LdapName name = null;
        try {
            name = new LdapName(personDN);
        } catch (InvalidNameException e) {
            e.printStackTrace();
        }

        AndFilter filter = new AndFilter();
        filter.and(new EqualsFilter("managedObjects", personDN));

        return ldapTemplate.find(name, filter, searchControls, Person.class);
    }

    @Override
    public boolean authenticateUser(LdapGroupServerInfo serverInfo,
            String userDN, String credentials) {
        openLdapConnection(serverInfo);

        DirContext ctx = null;
        try {
            ctx = ldapTemplate.getContextSource().getContext(userDN,
                    credentials);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            LdapUtils.closeContext(ctx);
        }
    }
    ...
}

上文主要是通过ldapTemplate来进行数据请求和处理的,需要先定义一个方法来开启ldap连接,通过contextSource来建立连接:
contextSource.setReferral(“follow”) 我们只需要部分数据,这个设置可以防止其报javax.naming.PartialResultException异常。
follow模式在多层级下会影响读取速度,可以设置为ignore。
contextSource.afterPropertiesSet() 表示不是基于配置模式来配置contextSource的。

至此,我们就可以通过这个Repository来进行数据交互了,当然还可以继续扩展改类来实现更多的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值