学习SpringSecurity时,看到LDAP认证,不了解LDAP根本无从下手。所以转头学习了一下LDAP,搭建了一个DEMO,仅作记录。
LDAP(Lightweight Directory Access Protocol) 轻量级目录访问协议,LDAP目录以树状的层次结构来存储数据。
概念性的东西就不多说了,说一下LDAP数据交换格式中使用的比较多的几个概念:
DN = Distignuished Name
CN = Common Name
OU = Organiazational Unit
DC = Domain Component
DN 相当于全路径名,唯一的标识,比如一个用户的DN可能是 cn=talyer,ou=developers,dc=example,dc=com
然后就是objectclass和Attribute,在LDAP中,一个实体必须要有一个objectClass,粗略的讲就是数据类型了,objectClass分为三种,Abstract,Structural,AUXIALIARY,objectClass也可以有继承关系等。要定义一个实体就一定要有一个Structural类型的objectClass,因为其中有一个Abstract类型的顶级objectClass:Top,它有一个must Attribute:objectClass。
Attribute就相当于JAVA类中的属性了,其中也为两种类型:MUST和MAY,MUST是实体必须提供的属性,MAY是可有可无的。拿objectClass:Person来举例,它有6个属性:
cn,sn,userPassword,telephoneNumber,seeAlso,description
其中cn和sn的必须提供的,其它4个是可选的。
知道这些大概就可以开始搭建DEMO了。
首先需要一个LDAP服务器,我使用的是ApacheDS,是Apache基金会下的一个LDAP服务器,使用JAVA编写的,ApacheDS官网,相关的配置官网都有比较详细的说明
然后就开始搭建环境啦,使用的MAVEN项目。SpringLDAP是Spring的一个子项目,所以需要依赖于Spring
<properties>
<org.springframework-version>4.1.0.RELEASE</org.springframework-version>
<org.springframework.ldap-version>2.0.2.RELEASE</org.springframework.ldap-version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
<version>${org.springframework.ldap-version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
接下来就是配置文件了,LDAP的配置文件比较简单
<context:component-scan base-package="org.main"/>
<ldap:context-source url="ldap://127.0.0.1:10389" <!--apacheDS 安装之后的默认属性-->
base="dc=example,dc=com"
username="uid=admin,ou=system"
password="secret"
/>
<ldap:ldap-template id="ldapTemplate" />
<!-- 自动扫描org.main包下继承了ldap标准CURD接口的接口(我们用的是ldapRepository),
并基于这些接口为他们创建标准实现-->
<ldap:repositories base-package="org.main" />
SpringLdap使用ODM(Object Directory Mapping)进行封装。创建一个实体类,使用Annotation方式配置即可,下面只贴出了User相关的类。
User实体类
@Entry(objectClasses = { "top","person" },base="ou=Departments")
public class User {
public static final String USER_ROLE = "USER_ROLE";
public static final String DEPARTMENT_OU = "Departments";
@Id
private Name dn;
@Attribute(name="cn")
@DnAttribute(value="cn",index=3)
private String fullName;
@Attribute(name="sn")
private String lastName;
@DnAttribute(value="ou",index=2)
@Transient
private String unit;
@DnAttribute(value="ou",index=1)
@Transient
private String department;
@Attribute(name="userPassword")
private String userPassword;
@Attribute(name="telephoneNumber")
private String telephoneNumber;
@Attribute(name="description")
private String description;
}
getter、setter方法、equals和hashCode方法就没帖出来了,@Entry注解表明这是一个ldap的实体映射类,objectClass为person和top,之前说过,top是一个顶级abstract类型的objectClass。baseDn为ou=Departments
@Id标注的是这个实体的DN,@Attribute表明这是objectClass的一个属性,@Dnattribute标注的属性都是属于自动构建DN时的一部分
UserRepo
/**
**LdapRepository接口包含标准CURD方法
* @author lc
*
*/
public interface UserRepo extends LdapRepository<User>{
}
UserRepo接口十分简单,只是继承了LdapRepository接口。由于之前我们配置文件进行了配置,Spring会自动为实现了这个接口的接口创建标准实现。
UserService
@Service("userService")
public class UserServiceImpl extends CommonRepo implements UserService{
@Autowired
private UserRepo userRepo;
public void setUserRepo(UserRepo userRepo) {
this.userRepo = userRepo;
}
@Autowired
private GroupRepo groupRepo;
public void setGroupRepo(GroupRepo groupRepo) {
this.groupRepo = groupRepo;
}
/**
* 创建User对象。
* @param user
* @param group 用户所在的组
*/
@Override
public User create(User user, String group) {
User savedUser = userRepo.save(user);
Group grp = groupRepo.findOne(LdapUtils.newLdapName(group)); //使用组名查询组
grp.addMember(savedUser.getDn()); //将保存的用户加入组
groupRepo.save(grp);
return savedUser;
}
/**
* 根据用户名查询User对象
* @param userName 用户名
*/
public User findUserByUserName(String userName) {
LdapQuery query = this.getQuery().attributes("cn").where("objectclass")
.is("person").and("cn").is(userName);
return this.getLdapTemplate().findOne(query, User.class);
}
public LdapName toAbsoluteDn(Name relativeName) {
return LdapNameBuilder.newInstance(Group.BASE)
.add(relativeName)
.build();
}
}
Test
@Test
public void initUser() {
UserService userService = (UserService) getapp().getBean("userService");
User user = new User();
user.setDepartment("IT");
user.setUnit("PROJECTTHREE");
user.setFullName("gino");
user.setUserPassword("111111");
user.setLastName("G");
userService.create(user, "cn=ROLE_USER,ou=Groups");
}
完整项目下载地址:点击进入下载页