springboot集成Ldap

一、什么是Ldap
轻型目录访问协议(英文:Lightweight Directory Access Protocol,缩写:LDAP,/ˈɛldæp/)是一个开放的,中立的,工业标准的应用协议,通过IP协议提供访问控制和维护分布式信息的目录信息。
二、为什么需要Ldap
这里举个例子,一个公司内部有很多系统,每个系统都有独立的用户名和密码。密码太多,有时候想不起来哪个密码对应的是哪个系统。后续如果又新增一个项目,还要在开发和维护一套用户和密码。如何才能系统整合,以此做到账号的打通,使多套系统共用一个用户名和密码。如果要求不高的话Ldap就能很好的满足要求,如果要求比较高的话可以开发一个统一门户管理平台(统一门户平台不在本次讨论范围)。
三、Ldap介绍
在 LDAP 里, 一切都是等级化的,或者称之为层级化(hiearchical)。
一棵树有树干,树枝和树叶;树叶长在树枝上,树枝依附于树干。这就是一个简单的层级结构。LDAP 的结构同一棵树类似。假设 LDAP 里存储的是公司的信息,那么可以把公司(company)本身理解为树干,公司里面的各个部门,比如组(group),理解为树干,把用户(user)理解为树叶。这样的结构称之为目录信息树(DIrectory Information Tree,DIT)。

CN, OU, DC 都是 LDAP 连接服务器的端字符串中的区别名称(DN, distinguished name)
LDAP连接服务器的连接字串格式为:ldap://servername/DN
其中DN有三个属性,分别是CN,OU,DC
LDAP是一种通讯协议,如同HTTP是一种协议一样的!
在 LDAP 目录中,
· DC (Domain Component)
· CN (Common Name)
· OU (Organizational Unit)
LDAP 目录类似于文件系统目录。
下列目录:
DC=Remeber,DC=Da,DC=microsoft,DC=com
如果我们类比文件系统的话,可被看作如下文件路径:
Com\Microsoft\Da\Remeber
例如:CN=testsan,OU=developer,DC=domainname,DC=com
在上面的代码中 cn=testsan可能代表一个用户名,ou=developer 代表一个 active directory 中的组织单位。这句话的含义可能就是说明 test 这个对象处在domainname.com 域的 developer 组织单元中。

四、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”(一条记录的名称)
dn Distinguished Name “uid=songtao.xu,ou=oa组,dc=example,dc=com”,一条记录的位置(唯一)
rdn Relative dn 相对辨别名,类似于文件系统中的相对路径,它是与目录树结构无关的部分,如“uid=tom”或“cn= Thomas Johansson”
sn Surname 姓,如“许”
五、集成过程
1、添加依赖

org.springframework.boot
spring-boot-starter-data-ldap

1、在application.properties中添加如下配置
ldap:

服务地址 生产环境

urls: xxxx
base: OU=组织机构,DC=xxxx,DC=ad
username: xxxx
password: xxxx
2、通过如上两步,我们已经完成了springboot集成ldap 。
3、我们建三个方法,方法一:获得所有的域用户,方法二:获得所有的部门,方法三:登录验证
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;

}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Boot 中,可以使用 Spring LDAP 来实现 LDAP 认证。具体步骤如下: 1. 配置 pom.xml,引入 Spring LDAP 相关依赖: ```xml <dependency> <groupId>org.springframework.ldap</groupId> <artifactId>spring-ldap-core</artifactId> <version>${spring-ldap.version}</version> </dependency> ``` 2. 配置 application.yml,设置 LDAP 连接信息: ```yaml spring: ldap: urls: ldap://localhost:389 base: dc=my-domain,dc=com username: cn=Manager,dc=my-domain,dc=com password: password ``` 3. 实现 LdapUserDetailsMapper,将 LDAP 用户信息映射为 Spring Security User 对象: ```java @Component public class LdapUserDetailsMapper implements UserDetailsContextMapper { @Override public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) { String password = (String) ctx.getObjectAttribute("userPassword"); List<GrantedAuthority> grantedAuthorities = new ArrayList<>(); for (GrantedAuthority authority : authorities) { grantedAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority())); } return new User(username, password, grantedAuthorities); } @Override public void mapUserToContext(UserDetails user, DirContextAdapter ctx) { throw new UnsupportedOperationException("Not supported yet."); } } ``` 这里将 LDAP 中的 "userPassword" 属性作为密码,LDAP 中的权限信息作为 Spring Security 的 GrantedAuthority 对象,最终将它们封装为一个 User 对象。 4. 配置 WebSecurityConfigurerAdapter,实现 LDAP 认证: ```java @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private LdapUserDetailsMapper ldapUserDetailsMapper; @Autowired private Environment env; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasRole("USER") .anyRequest().authenticated() .and() .formLogin() .and() .logout(); http.csrf().disable(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.ldapAuthentication() .userSearchBase(env.getProperty("spring.ldap.user-search-base")) .userSearchFilter(env.getProperty("spring.ldap.user-search-filter")) .groupSearchBase(env.getProperty("spring.ldap.group-search-base")) .groupSearchFilter(env.getProperty("spring.ldap.group-search-filter")) .contextSource() .url(env.getProperty("spring.ldap.urls")) .managerDn(env.getProperty("spring.ldap.username")) .managerPassword(env.getProperty("spring.ldap.password")) .and() .userDetailsContextMapper(ldapUserDetailsMapper); } } ``` 这样就可以通过 LDAP 认证来控制访问权限了。在这个例子中,请求 "/admin/**" 的用户需要拥有 ADMIN 角色,请求 "/user/**" 的用户需要拥有 USER 角色,其他请求需要认证通过即可访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~有思想的码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值