9.2.3 基于 LDAP 进行认证
为了让 Spring Security 使用基于 LDAP 的认证,我们可以使用 ldapAuthentication() 方法。这个方法在功能上类似于 jdbcAuthentication(),只不过是 LDAP 版本。如下的 configure() 方法展现了 LDAP 认证的简单配置:
1
@Override
2
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
3
auth
4
.ldapAuthentication()
5
.userSearchFilter("{uid={0}}")
6
.groupSearchFilter("member={0}");
7
}
Copied!
方法 userSearchFilter() 和 groupSearchFilter() 用来为基础 LDAP 查询提供过滤条件,它们分别用于搜索用户和组。默认情况下,对于用户和组的基础查询都是空的,也就是表明搜索会在 LDAP 层级结构的根开始。但是我们可以通过指定查询基础来改变这个默认行为:
1
@Override
2
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
3
auth
4
.ldapAuthentication()
5
.userSearchBase("ou=people");
6
.userSearchFilter("{uid={0}}")
7
.groupSearchBase("ou=groups");
8
.groupSearchFilter("member={0}");
9
}
Copied!
userSearchBase() 属性为查找用户提供了基础查询。同样,groupSearch-Base() 为查找组指定了基础查询。我们声明用户应该在名为 people 的组织单元下搜索而不是从根开始。而组应该在名为 groups 的组织单元下搜索。
配置密码比对
基于 LDAP 进行认证的默认策略是进行绑定操作,直接通过 LDAP 服务器认证用户。另一种可选的方式是进行比对操作。这涉及将输入的密码发送到 LDAP 目录上,并要求服务器将这个密码和用户的密码进行比对。因为比对是在 LDAP 服务器内完成的,实际的密码能保持私密。 如果你希望通过密码比对进行认证,可以通过声明 passwordCompare() 方法来实现:
1
@Override
2
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
3
auth
4
.ldapAuthentication()
5
.userSearchBase("ou=people");
6
.userSearchFilter("{uid={0}}")
7
.groupSearchBase("ou=groups");
8
.groupSearchFilter("member={0}")
9
.passwordCompare();
10
}
Copied!
默认情况下,在登录表单中提供的密码将会与用户的 LDAP 条目中的 userPassword 属性进行比对。如果密码被保存在不同的属性中,可以通过 passwordAttribute() 方法来声明密码属性的名称:
1
@Override
2
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
3
auth
4
.ldapAuthentication()
5
.userSearchBase("ou=people");
6
.userSearchFilter("{uid={0}}")
7
.groupSearchBase("ou=groups");
8
.groupSearchFilter("member={0}")
9
.passwordCompare()
10
.passwordEncoder(new Md5PasswordEncoder())
11
.passwordAttribute("passcode");
12
}
Copied!
在本例中,我们指定了要与给定密码进行比对的是“passcode”属性。另外,我们还可以指定密码转码器。在进行服务器端密码比对时,有一点非常好,那就是实际的密码在服务器端是私密的。但是进行尝试的密码还是需要通过线路传输到 LDAP 服务器上,这可能会被黑客所拦截。为了避免这一点,我们可以通过调用 passwordEncoder() 方法指定加密策略。
在本示例中,密码会进行 MD5 加密。这需要 LDAP 服务器上密码也使用 MD5 进行加密。
引用远程的 LDAP 服务器
到目前为止,我们忽略的一件事就是 LDAP 和实际的数据在哪里。我们很开心地配置 Spring 使用 LDAP 服务器进行认证,但是服务器在哪里呢?
默认情况下,Spring Security 的 LDAP 认证假设 LDAP 服务器监听本机的 33389 端口。但是,如果你的 LDAP 服务器在另一台机器上,那么可以使用 contextSource() 方法来配置这个地址:
1
@Override
2
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
3
auth
4
.ldapAuthentication()
5
.userSearchBase("ou=people");
6
.userSearchFilter("{uid={0}}")
7
.groupSearchBase("ou=groups");
8
.groupSearchFilter("member={0}")
9
.contextSource()
10
.url("ldap://habuma.com:389/dc=habuma,dc=com");
11
}
Copied!
contextSource() 方法会返回一个 ContextSourceBuilder 对象,这个对象除了其他功能以外,还提供了 url() 方法用来指定 LDAP 服务器的地址。
配置嵌入式的 LDAP 服务器
如果你没有现成的 LDAP 服务器供认证使用,Spring Security 还为我们提供了嵌入式的 LDAP 服务器。我们不再需要设置远程 LDAP 服务器的 URL,只需通过 root() 方法指定嵌入式服务器的根前缀就可以了:
1
@Override
2
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
3
auth
4
.ldapAuthentication()
5
.userSearchBase("ou=people");
6
.userSearchFilter("{uid={0}}")
7
.groupSearchBase("ou=groups");
8
.groupSearchFilter("member={0}")
9
.contextSource()
10
.root("dc=habuma,dc=com");
11
}
Copied!
当 LDAP 服务器启动时,它会尝试在类路径下寻找 LDIF 文件来加载数据。LDIF(LDAP Data Interchange Format,LDAP数据交换格式)是以文本文件展现 LDAP 数据的标准方式。每条记录可以有一行或多行,每项包含一个名值对。记录之间通过空行进行分割。
如果你不想让 Spring 从整个根路径下搜索 LDIF 文件的话,那么可以通过调用 ldif() 方法来明确指定加载哪个 LDIF 文件:
1
@Override
2
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
3
auth
4
.ldapAuthentication()
5
.userSearchBase("ou=people");
6
.userSearchFilter("{uid={0}}")
7
.groupSearchBase("ou=groups");
8
.groupSearchFilter("member={0}")
9
.contextSource()
10
.root("dc=habuma,dc=com")
11
.ldif("classpath:users.ldif");
12
}
Copied!
在这里,我们明确要求 LDAP 服务器从类路径根目录下的 users.ldif 文件中加载内容。如果你比较好奇的话,如下就是一个包含用户数据 LDIF 文件,我们可以使用它来加载嵌入式 LDAP 服务器:
1
dn: ou=groups,dc=habuma,dc=com
2
objectclass: top
3
objectclass: organizationalUnit
4
ou: groups
5
dn: ou=people,dc=habuma,dc=com
6
objectclass: top
7
objectclass: organizationalUnit
8
ou: people
9
dn: uid=habuma, ou=people, dc=hab\oma, dc=com
10
objectclass: top
11
objectclass: person
12
objectclass: organizationalPerson
13
objectclass: inetOrgPerson
14
cn: Craig Walls
15
sn: Walls
16
uid: habuma
17
userPassword: password
18
dn: uid=jsmith,ou=people,dc=habuma,dc=com
19
objectclass: top
20
objectclass: person
21
objectclass: organizationalPerson
22
objectclass: inetOrgPerson
23
cn: John Smith
24
sn: Smith
25
uid: jsmith
26
userPassword: password
27
dn: cn=spittr,outgroups,dc=habuma,dc=com
28
objectclass: top
29
objectclass: groupOfNames
30
cn: spittr
31
member: uid=habuma,ou=people,dc=habuma,dc=com
Copied!
Spring Security 内置的用户存储非常便利,并且涵盖了最为常用的用户场景。但是,如果你的认证需求不是那么通用的话,那么就需要创建并配置自定义的用户详细信息服务了。
Last modified 2yr ago
Copy link