SpringBoot集成Ldap
什么是Ldap轻型目录访问协议(英文:Lightweight Directory Access Protocol,缩写:LDAP,/ˈɛldæp/)是一个开放的,中立的,工业标准的应用协议,通过IP协议提供访问控制和维护分布式信息的目录信息。为什么需要Ldap这里举个例子,一个公司内部有很多系统,每个系统都有独立的用户名和密码。密码太多,有时候想不起来哪个密码对应的是哪个系统。后续如果又新增一个项
目录
什么是Ldap
轻型目录访问协议(英文:Lightweight Directory Access Protocol,缩写:LDAP,/ˈɛldæp/)是一个开放的,中立的,工业标准的应用协议,通过IP协议提供访问控制和维护分布式信息的目录信息。
为什么需要Ldap
这里举个例子,一个公司内部有很多系统,每个系统都有独立的用户名和密码。密码太多,有时候想不起来哪个密码对应的是哪个系统。后续如果又新增一个项目,还要在开发和维护一套用户和密码。如何才能系统整合,以此做到账号的打通,使多套系统共用一个用户名和密码。如果要求不高的话Ldap就能很好的满足要求,如果要求比较高的话可以开发一个统一门户管理平台(统一门户平台不在本次讨论范围)。
Ldap基本模型
每一个系统、协议都会有属于自己的模型,LDAP也不例外,在了解LDAP的基本模型之前我们需要先了解几个LDAP的目录树概念:
(一)目录树概念
1. 目录树:在一个目录服务系统中,整个目录信息集可以表示为一个目录信息树,树中的每个节点是一个条目。
2. 条目:每个条目就是一条记录,每个条目有自己的唯一可区别的名称(DN)。
3. 对象类:与某个实体类型对应的一组属性,对象类是可以继承的,这样父类的必须属性也会被继承下来。
4. 属性:描述条目的某个方面的信息,一个属性由一个属性类型和一个或多个属性值组成,属性有必须属性和非必须属性。
(二)DC、UID、OU、CN、SN、DN、RDN
关键字 |
英文全称 |
含义 |
dc |
Domain Component |
域名的部分,其格式是将完整的域名分成几部分,如域名为example.com变成dc=example,dc=com(一条记录的所属位置) |
uid |
User Id |
用户ID songtao.xu(一条记录的ID) |
ou |
Organization Unit |
组织单位,组织单位可以包含其他各种对象(包括其他组织单元),如“oa组”(一条记录的所属组织) |
cn |
Common Name |
公共名称,如“Thomas Johansson”(一条记录的名称) |
sn |
Surname |
姓,如“许” |
dn |
Distinguished Name |
“uid=songtao.xu,ou=oa组,dc=example,dc=com”,一条记录的位置(唯一) |
rdn |
Relative dn |
相对辨别名,类似于文件系统中的相对路径,它是与目录树结构无关的部分,如“uid=tom”或“cn= Thomas Johansson” |
Springboot集成Ldap
在pom中添加spring-boot-starter-data-ldap依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.13.RELEASE</version>
<relativePath />
</parent>
<groupId>com.ldap</groupId>
<artifactId>ldapdemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-ldap</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在application.properties中添加如下配置
通过如上两步,我们已经完成了springboot集成ldap 。
Springboot操作Ldap
我们建三个方法,方法一:获得所有的域用户,方法二:获得所有的部门,方法三:登录验证
方法如下:
package com.ldap.demo.service.impl;
import static org.springframework.ldap.query.LdapQueryBuilder.query;
import java.util.List;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.support.LdapUtils;
import org.springframework.stereotype.Service;
import com.ldap.demo.service.LdapService;
import com.ldap.demo.service.entity.LdapDept;
import com.ldap.demo.service.entity.Ldapuser;
@Service
public class LdapServiceImpl implements LdapService {
@Autowired
private LdapTemplate ldapTemplate;
/**
* 获得域用户
*/
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public List<Ldapuser> getPersonList() {
//下面也可以使用filter查询方式,filter 为(&(objectClass=user)(!(objectClass=computer))
return ldapTemplate.search(query().where("objectclass").is("user").and("objectclass").not().is("computer"),
new AttributesMapper() {
@Override
public Ldapuser mapFromAttributes(Attributes attr) throws NamingException {
//如果不知道ldap中有哪些属性,可以使用下面这种方式打印
// NamingEnumeration<? extends Attribute> att = attr.getAll();
//while (att.hasMore()) {
// Attribute a = att.next();
// System.out.println(a.getID());
//}
Ldapuser person = new Ldapuser();
String distingugihedName = (String) attr.get("distinguishedName").get();
person.setUserName((String) attr.get("sAMAccountName").get());
person.setRealName((String) attr.get("cn").get());
String departmentName = StringUtils.substringAfter(distingugihedName.split(",")[1], "OU=");
person.setUnitName(departmentName);
if (attr.get("description") != null) {
person.setDescription((String) attr.get("description").get());
}
if (attr.get("mobile") != null) {
person.setPhone((String) attr.get("mobile").get());
}
if (attr.get("telephoneNumber") != null) {
person.setTelephone((String) attr.get("telephoneNumber").get());
}
if (attr.get("userPrincipalName") != null) {
person.setEmail((String) attr.get("userPrincipalName").get());
}
return person;
}
});
}
/**
* 获得部门
*/
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public List<LdapDept> getDeptList() {
return ldapTemplate.search(
下面也可以使用filter查询方式,filter 为(|(objectclass=organizationalunit)(objectclass=organization))
query().where("objectclass").is("organizationalunit").or("objectclass").is("organization"),
new AttributesMapper() {
@Override
public LdapDept mapFromAttributes(Attributes attr) throws NamingException {
//如果不知道ldap中有哪些属性,可以使用下面这种方式打印
// NamingEnumeration<? extends Attribute> att = attr.getAll();
//while (att.hasMore()) {
// Attribute a = att.next();
// System.out.println(a.getID());
//}
LdapDept dept = new LdapDept();
dept.setDeptId(attr.get("ou").toString().split(":")[1].trim());
if (attr.get("description") != null) {
dept.setDeptName(attr.get("description").toString().split(":")[1].trim());
}
return dept;
}
});
}
/**
* 根据用户名密码验证
* @param userCn 用户名
* @param pwd 密码
* @return
*/
@SuppressWarnings("unchecked")
@Override
public boolean authenticate(String userCn, String pwd) {
DirContext ctx = null;
System.out.println(userCn + ":" + pwd);
try {
//调用ldap 的 authenticate方法检验
String filter = "(&(objectclass=user)(!(objectClass=computer))(sAMAccountName=" + userCn + "))";
boolean authenticate = ldapTemplate.authenticate("", filter, pwd);
return authenticate;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
LdapUtils.closeContext(ctx);
}
}
}
Ldapuser代码如下:
package com.ldap.demo.service.entity;
import lombok.Data;
@Data
public class Ldapuser {
/**
* 用户名
*/
private String userName;
/**
* 邮箱
*/
private String email;
/**
* 手机号
*/
private String phone;
/**
* 座机号
*/
private String telephone;
/**
* 真实姓名
*/
private String realName;
/**
* 部门
*/
private String unitName;
/**
* 描述
*/
private String description;
}
LdapDept代码如下
package com.ldap.demo.service.entity;
import lombok.Data;
@Data
public class LdapDept {
/**
* 部门代码
*/
private String deptId;
/**
* 部门名称
*/
private String deptName;
}
我们建一个测试类进行测试:
package com.ldap.demo;
import javax.naming.NamingException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ldap.demo.service.impl.LdapServiceImpl;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class LdapTest {
@Autowired
private LdapServiceImpl ldapService;
@Before
public void before() {
System.out.println("start=============");
}
@Test
public void testStartUp() throws NamingException {
ldapService.getPersonList().forEach(p -> {
System.out.println("用户:" + p);
});
ldapService.getDeptList().forEach(d -> {
System.out.println("部门:" + d);
});
System.out.println("登录验证结果:" + ldapService.authenticate("test", "12344556"));
}
}
测试结果如下:
更多推荐
所有评论(0)