一、什么是LDAP
LDAP是轻量级目录拜访协定的简称。
目录是一个为查问、浏览和搜寻而优化的数据库,它成树状构造组织数据,相似文件目录一样。
二、为什么要用LDAP
咱们利用LDAP要达到的最终目标就是实现对立登录,比方咱们有多个零碎,每个零碎都是独立运行,然而咱们想要为了方便管理想要把这些用户全存在一起并且这些零碎登录时对立向这个库进行查问。
这时候咱们就用到了LDAP,那么
三、用docker部署LDAP和LDAP可视化界面
1、装置openldap
docker run \ -d \ -p 389:389 \ -p 636:636 \ -v /usr/local/ldap:/usr/local/ldap \ -v /data/openldap/ldap:/var/lib/ldap \ -v /data/openldap/slapd.d:/etc/ldap/slapd.d \ --env LDAP_ORGANISATION="imysh" \ --env LDAP_DOMAIN="imysh.com" \ --env LDAP_ADMIN_PASSWORD="123456" \ --name openldap \ --hostname openldap-host\ --network bridge \ osixia/openldap
其中 -p 389:389 \ TCP/IP拜访端口
-p 636:636 \ SSL连贯端口。
–network bridge 连贯默认的bridge网络(docker0)
–hostname openldap-host 设置容器主机名称为 openldap-host
–env LDAP_ORGANISATION=“imysh” 配置LDAP组织名称
–env LDAP_DOMAIN=“imysh.com” 配置LDAP域名
–env LDAP_ADMIN_PASSWORD=“123456” 配置LDAP明码
默认登录用户名:admin
2、装置可视化界面phpidapadmin
docker run \ -p 8081:80 \ --privileged \ --name phpldapadmin \ --env PHPLDAPADMIN_HTTPS=false \ --env PHPLDAPADMIN_LDAP_HOSTS=192.168.x.xxx \ --detach osixia/phpldapadmin
其中 PHPLDAPADMIN_LDAP_HOSTS 为配置openLDAP的IP或域名,咱们是在本地起的,所以填写咱们本机IP即可。
查问本机IP:ifconfig | grep "inet"
存储形式
不像咱们熟知的关系数据库, 数据都在表中,一行一行的,高深莫测,这个OpenLDAP是以树的形式存储的。 比方一个人的信息是这样的:
名词解释:
dc:域组织(能够把它当作关系型中的库)
比方将 http://liming.tcom这样的域名,能够拆成 dc=liming,dc=com这样的模式。
ou:指代组织单元、部门
cn:通用名称,个别为用户名
dn:用来惟一标识一项的门路。(一条dn就相似于关系型数据库中的一条数据)
例:
比方这个张三的dn:cn=zhang san,cn=newgroup,dc=imysh,dc=com
拜访治理首页
拜访: 127.0.0.1:8081
用咱们初始化的管理员账号登录
账号:cn=admin,dc=imysh,dc=com
明码:123456
新建部门、组和用户
新建部门(ou):
新建组(cn)
新建用户
咱们能够在新建用户时配置他的姓氏名称以及所属组、用户名、明码、加密形式等信息。
四、SpringBoot集成LDAP
所用依赖:
<dependency> <groupId>com.sun</groupId> <artifactId>ldapbp</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.springframework.ldap</groupId> <artifactId>spring-ldap-core</artifactId> <version>2.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>compile</scope> </dependency>
配置:
/** * LDAP 的主动配置类 * * 实现连贯 及LdapTemplate生成 */@Configurationpublic class LdapConfiguration { private LdapTemplate ldapTemplate; @Bean public LdapContextSource contextSource() { LdapContextSource contextSource = new LdapContextSource(); Map<String, Object> config = new HashMap(); contextSource.setUrl(LdapConstans.url); contextSource.setBase(LdapConstans.BASE_DC); contextSource.setUserDn(LdapConstans.username); contextSource.setPassword(LdapConstans.password); // 解决 乱码 的要害一句 config.put("java.naming.ldap.attributes.binary", "objectGUID"); contextSource.setPooled(true); contextSource.setBaseEnvironmentProperties(config); return contextSource; } @Bean public LdapTemplate ldapTemplate() { if (null == ldapTemplate) ldapTemplate = new LdapTemplate(contextSource()); return ldapTemplate; }}
通过下面的代码,在IOC容器实现bean的定义,咱们在内部就能够注入应用LdapTemplate了
LdapTemplate实现CRUD性能:
建设person类:
@Data@Entry(base = "cn=group,ou=department", objectClasses="inetOrgPerson")public class Person { /** * 此字段不能少 */ @Id private Name id; @DnAttribute(value = "uid", index = 3) private String uid; @Attribute(name = "cn") private String commonName; @Attribute(name = "sn") private String myUerName; private String userPassword;}
新增person
@Test public void addPerson() { Person person = new Person(); person.setUid("uid:15"); person.setMyUerName("liMing"); person.setCommonName("liming"); person.setUserPassword("123456"); ldapTemplate.create(person); }
后果:
查问person
@Testpublic void getUsers() { String filter = "(&(objectclass=inetOrgPerson))"; List<Person> list = ldapTemplate.search("cn=group,ou=department", filter, new AttributesMapper() { @SneakyThrows @Override public Object mapFromAttributes(Attributes attributes) throws NamingException { // 能够通过上面办法打印属性 NamingEnumeration<? extends Attribute> att = attributes.getAll(); while (att.hasMore()) { Attribute a = att.next(); System.out.println(a.getID() + "=" + a.get()); } Person user = new Person(); Attribute a = attributes.get("sn"); if (a != null) user.setMyUerName((String)a.get()); a = attributes.get("userPassword"); if (a != null) user.setUserPassword(a.get().toString()); a = attributes.get("cn"); if (a != null) user.setCommonName((String) a.get()); return user; } }); System.out.println(list); }
对于其中的filter要留神filter整体要在括号里,否则会报如下谬误:
org.springframework.ldap.InvalidSearchFilterException: invalid attribute description; nested exception is javax.naming.directory.InvalidSearchFilterException: invalid attribute description; remaining name 'cn=group,ou=department'
- 获取域列表,如果要获取确定的某一个域,filter能够这样写: (&(objectclass=dcObject)&(dc=imysh))
- 获取组织列表,如果要获取确定的某一个组织,filter能够这样写: (&(objectclass=organizationalUnit)&(ou=people)
- 获取people列表,如果要获取某一个确定的人,filter能够这样写: (&(objectclass=inetOrgPerson)&(uid=uid:13))
后果:
更新
@Test public void update(){ String oldPersonDn = " uid=uid:15,cn=group,ou=department"; Person newPerson = new Person(); newPerson.setMyUerName("newLiming"); newPerson.setCommonName("newCommentName"); ldapTemplate.modifyAttributes(oldPersonDn, new ModificationItem[] { new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("cn", newPerson.getCommonName().trim())), new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("sn", newPerson.getMyUerName().trim())), }); }
更新就是替换属性,应用ModificationItem类进行解决。
就像咱们之前应用的数据库一样,最简略的就是通过ID来进行更新,也就相当于这里的dn
后果:
删除
@Test public void delete() { String PersonDn = " uid=uid:15,cn=group,ou=department"; ldapTemplate.unbind(PersonDn); }
后果:
删除也就是解绑的过程,间接调用unbind即可