Spring Boot 连接LDAP

本文是Spring Boot系列文集中关于LDAP连接相关操作的一文。仅仅涉及基本的使用ODM来快速实现LDAP增删改查操作。详细的关于Spring LDAP的其他操作,可以参考翻译的官方文档


本文目的:使用Spring Boot构建项目,帮助读者快速配置并使用Spring LDAP操作LDAP。大致步骤如下:

  • 1.创建Spring Boot项目(约1分钟)
  • 2.添加pom.xml文件中Spring LDAP依赖(约1分钟)
  • 3.配置Spring LDAP连接信息(约1分钟)
  • 4.创建实体类作为LDAP中的entry映射(ODM映射功能,类似ORM)
  • 5.使用ldapTemplate书写service层的方法(约3分钟)
  • 6.编写controller层(约3分钟)

本文使用IDEA来进行开发,在IDEA中新建Spirng Boot项目以及Spring Boot基础知识快速入门可以参考:
2小时学会Spring Boot

1.创建Spring Boot项目(约1分钟)

IDEA中点击file - new - project


图1

如上图,选择左侧的 Spring Initializr帮助初始化spring项目,配置好SDK后,点击next。


图2

点击后,如图2,如果只是做demo,该页面默认即可,点击next。
图3

如图3,我们选择web,右侧会显示web相关的组件,我们选择右侧中的Web,将其前面的框勾选上。这代表在创建的spring boot项目中会引入web相关的依赖。点击next。


图4

如图4,这里自己命名即可,点击finish。

2.添加pom.xml文件中Spring LDAP依赖(约1分钟)

图5

如上图图5,在项目中双击pom.xml来添加依赖。


图6

如图6所示,文件中已经加载了spring-boot-starter-web依赖,我们要使用Spring LDAP来操作LDAP服务器需要添加spring-boot-starter-data-ldap。该依赖会自动加载spring-ldap-core 与 spring-data-ldap依赖。其中spring-ldap-core是ldap操作的核心依赖,而spring-data-ldap提供了ODM的功能,能够简化操作。我们可以在项目的External Libraries中看到这两个依赖,如下图图7中三个黄色高亮处:


图7

3.配置Spring LDAP连接信息

图8

如上图图8,根据spring boot官网对ldap配置的说明来配置,可以看这里。这样配置之后,spring boot会自动读取该配置。xml的配置可以参考翻译的官方文档

4.创建实体类作为LDAP中的entry映射

本例中使用ODM功能,极大的简化了LDAP的操作,关于ODM更多的信息,可以参考翻译的官方文档
我们在项目中创建如下结构:

图9

现在,我们在entry包下写与entry互相映射的实体类。其中,我的LDAP结构如下
图10

新建Person类

package com.example.demo.entry;

import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;
import org.springframework.ldap.support.LdapNameBuilder;

import javax.naming.Name;

/**
 * @Author: geng_pool
 * @Description:
 * @Date: Created in 2017/12/27 10:24
 * @Modified by:
 */
@Entry(objectClasses = {"organizationalPerson","person","top"},base = "o=myorg")
public class Person {

    @Id
    @JsonIgnore
    private Name dn;

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

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

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

    public Person(String cn) {
        Name dn = LdapNameBuilder.newInstance()
                .add("o", "myorg")
                .add("cn", cn)
                .build();
        this.dn = dn;
    }
    public Person(){}

    /* getter   */
    public Name getDn() {
        return dn;
    }

    public String getCn() {
        return cn;
    }

    public String getSn() {
        return sn;
    }

    public String getUserPassword() {
        return userPassword;
    }

    /* setter   */
    public void setDn(Name dn) {
        this.dn = dn;
    }

    public void setCn(String cn) {
        this.cn = cn;
        if(this.dn==null){
            Name dn = LdapNameBuilder.newInstance()
                    .add("o", "myorg")
                    .add("cn", cn)
                    .build();
            this.dn = dn;
        }
    }

    public void setSn(String sn) {
        this.sn = sn;
    }

    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }

    @Override
    public String toString() {
        return "Person{" +
                "dn=" + dn.toString() +
                ", cn='" + cn + '\'' +
                ", sn='" + sn + '\'' +
                ", userPassword='" + userPassword + '\'' +
                '}';
    }
}

注意@Entry与@Id为必须的。而@JsonIgnore是为了将person传给前端时不报错,因为Name类型的无法自动解析成json格式。注意我为了方便,在 public Person(String cn) {}构造方法中写上了DN值的生成方法,在setCn中也写上了该方法,当然存在代码重复问题,忽略就好。

5.使用ldapTemplate书写service层的方法

在service包中,新建OdmPersonRepo类

package com.example.demo.service;

import com.example.demo.entry.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.stereotype.Service;

import static org.springframework.ldap.query.LdapQueryBuilder.query;

/**
 * @Author: geng_pool
 * @Description:
 * @Date: Created in 2017/12/27 10:37
 * @Modified by:
 */
@Service
public class OdmPersonRepo {

    @Autowired
    private LdapTemplate ldapTemplate;

    public Person create(Person person){
        ldapTemplate.create(person);
        return person;
    }

    public Person findByCn(String cn){
        return ldapTemplate.findOne(query().where("cn").is(cn),Person.class);
    }

    public Person modifyPerson(Person person){
        ldapTemplate.update(person);
        return person;
    }

    public void deletePerson(Person person){
        ldapTemplate.delete(person);
    }

}

可以看到,基本的增删改查操作都帮我们实现了,我们只要调用一下ldapTemplate中的方法即可。若要更自由的操作ldap的增删改查,可参阅翻译的官方文档

6.编写controller层

在controller包下,新建一个testController类来测试LDAP的操作。

package com.example.demo.controller;

import com.example.demo.entry.Person;
import com.example.demo.service.OdmPersonRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.web.bind.annotation.*;

/**
 * @Author: geng_pool
 * @Description:
 * @Date: Created in 2017/12/27 10:50
 * @Modified by:
 */
@RestController
public class testController {
    @Autowired
    private OdmPersonRepo odmPersonRepo;
    
    @RequestMapping(value = "/findOne",method = RequestMethod.POST)
    public Person findByCn(@RequestParam(name = "cn",required = true) String cn){
        return odmPersonRepo.findByCn(cn);
    }

    @PostMapping(value = "/create")
    public Person create(@RequestParam(name = "cn") String cn,@RequestParam(name = "sn") String sn,@RequestParam(name = "userPassword") String userPassworld){
        Person person = new Person();
        person.setCn(cn);
        person.setSn(sn);
        person.setUserPassword(userPassworld);
        return odmPersonRepo.create(person);
    }



    @PostMapping(value = "/update")
    public Person update(@RequestParam(name = "cn") String cn,@RequestParam(name = "sn") String sn,@RequestParam(name = "userPassword") String userPassworld){
        Person person = new Person();
        person.setCn(cn);
        person.setSn(sn);
        person.setUserPassword(userPassworld);
        return odmPersonRepo.modifyPerson(person);
    }

    @PostMapping(value = "/delete")
    public void delete(@RequestParam(name = "cn")String cn){
        Person person = new Person();
        person.setCn(cn);
        odmPersonRepo.deletePerson(person);
    }

}

至此,一个基本的demo完成啦。下面我们测试一下

测试

为了大家都能跟着步骤来,我就不使用Postman来测试,而是在浏览器中测试接口。、
启动spring boot,没有报错的话,打开浏览器到 localhost:8080/,按下F12,弹出开发者模式,找到console控制台方便我们发送测试语句。
首先,引入jquery.js。打开jquery.js,全选-复制-在console中粘贴-回车,如下图:

图11

显示为true,代表加载成功,我们可以使用jquery的ajax来测试了。

新增数据

图12

正如controller层的testController要求的那样,我们在地址 /create 上使用post方法,将数据cn sn userPassword传过去


图13

而在LDAP服务器中,也显示了新增的数据


图14

查找数据

图15

也能根据cn正确查找到数据。

修改数据

图16

我们查看LDAP中是否修改


图17

可以看到能够正常修改数据

删除数据

图18

查看LDAP中是否删除


图19

可以看到,数据被正确删除了。

其他说明

  • 刚才的例子中,代码有需要完善的地方,但对于demo演示来说完全可以忍受。大家可能也看到了这么做也有些缺点,我在update的时候,需要将修改后的person的所有属性值都传到后台来(这也不算啥缺点,关系数据库的更新也是这样),并且不能修改cn的值(这就是为什么其他例子中都是使用uid来作为dn的一部分,类似于关系数据库的主键的作用),因为修改后该entry的dn值就变化了,ODM就无法确定更新哪个数据。会报javax.naming.NameNotFoundException: [LDAP: error code 32 - No Such Object]错误。
  • 删除操作也像关系数据库的操作一样,直接给cn即可,这是因为我们在person类中setCn()方法内写了dn的生成函数,这样ODM才能根据被@Id所注释的dn来找到LDAP中的entry并执行删除操作。
  • 我们在Person类中写了Name类型的dn值的构建方法,但是我一开始按照官网的代码来写,总是出问题,在stackOverFlow中找到了答案。链接在这里
  • 想要更深入的了解,可以参考翻译的官方文档。了解更自由更个性化的操作。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容