学习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"); }
完整项目下载地址:点击进入下载页