一、引入spring-boot-starter-data-ldap依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-ldap</artifactId>
</dependency>

二、配置文件

1
2
3
4
5
6
spring:
ldap:
urls: ldap://xx.xx.xx.xx:389
base: OU=xxx,DC=xxx,DC=com
username: xxx@xx.com
password: xxx

在配置文件里填入地址、baseDN、用户名和密码信息

三、创建用户对象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;

import javax.naming.Name;

/**
* ldap协议person类
*/
@Data
@Entry(objectClasses = "person")
public class Person {

/**
* 唯一标识
*/
@Id
@JSONField(serialize = false)
private Name distinguishedName;

/**
* 登录账号
*/
@Attribute(name = "sAMAccountName")
private String loginName;

/**
* 用户姓名
*/
@Attribute(name = "cn")
private String name;

/**
* 权限码
*/
@Attribute(name = "userAccountControl")
private Integer userAccountControl;

/**
* 是否删除
*/
private Boolean isDelete;
}

四、用户登录

4.1 示例代码

1
2
3
4
5
6
7
8
9
10
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.EqualsFilter;

private final LdapTemplate ldapTemplate;
private static final String LDAP_USERNAME_ATTR = "sAMAccountName";

public void login(String userName, String password) {
EqualsFilter filter = new EqualsFilter(LDAP_USERNAME_ATTR, userName);
boolean result = ldapTemplate.authenticate("", filter.toString(), password);
}

基本逻辑就是调用ldapTemplate的authenticate方法来进行认证。

4.2 完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package com.cowave.meter.admin.user.service.impl;

import cn.hutool.core.util.IdUtil;
import com.cowave.commons.framework.access.Access;
import com.cowave.commons.framework.filter.security.AccessToken;
import com.cowave.commons.framework.filter.security.TokenService;
import com.cowave.commons.framework.support.mybatis.page.PageDO;
import com.cowave.commons.framework.util.Asserts;
import com.cowave.commons.framework.util.AssertsException;
import com.cowave.meter.admin.user.dao.SysDeptDao;
import com.cowave.meter.admin.user.dao.SysRoleDao;
import com.cowave.meter.admin.user.dao.SysUserDao;
import com.cowave.meter.admin.user.pojo.Person;
import com.cowave.meter.admin.user.pojo.SysDept;
import com.cowave.meter.admin.user.pojo.SysRole;
import com.cowave.meter.admin.user.pojo.SysUser;
import com.cowave.meter.admin.user.service.LdapService;
import com.cowave.meter.admin.user.service.SysUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.query.LdapQueryBuilder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class LdapServiceImpl implements LdapService {
private final LdapTemplate ldapTemplate;
private final TokenService tokenService;
private final SysUserDao sysUserDao;
private final SysUserService userService;
private final SysDeptDao sysDeptDao;
private final SysRoleDao sysRoleDao;
private final BCryptPasswordEncoder bcryptPasswordEncoder = new BCryptPasswordEncoder();
private static final String LDAP_USERNAME_ATTR = "sAMAccountName";

/**
* 域账号登录
*
* @param userName
* @param password
* @return
*/
@Override
public AccessToken domainLogin(String userName, String password) {
EqualsFilter filter = new EqualsFilter(LDAP_USERNAME_ATTR, userName);
boolean authenticate = ldapTemplate.authenticate("", filter.toString(), password);
if (!authenticate) {
throw new AssertsException("auth.failed");
}
Boolean domainUserAccountExist = sysUserDao.domainUserAccountExist(userName);
if (Boolean.FALSE.equals(domainUserAccountExist)) {
LdapQueryBuilder ldapQuery = LdapQueryBuilder.query();
ldapQuery.filter(filter);
Person person = ldapTemplate.findOne(ldapQuery, Person.class);
if (ObjectUtils.isEmpty(person)) {
throw new AssertsException("user.notexist");
}

SysUser sysUser = new SysUser();
sysUser.setUserAccount(userName);
Asserts.isFalse(userService.userAccountExist(sysUser), "账户名已存在");
sysUser.setUserName(person.getName());
sysUser.setUserPasswd(bcryptPasswordEncoder.encode(password));
sysUser.setDomainUserAccount(userName);
// 设置部门
SysDept sysDept = sysDeptDao.queryRootDept();
if (!ObjectUtils.isEmpty(sysDept)) {
sysUser.setDeptId(sysDept.getDeptId());
}
// 设置角色
PageDO<SysRole> sysRolePageDO = sysRoleDao.queryPage(null, "2", 1, 1);
if (sysRolePageDO.getPages() > 0) {
SysRole sysRole = sysRolePageDO.getList().get(0);
sysUser.setRoleId(sysRole.getRoleId());
}
userService.saveOrUpdate(sysUser);
}
SysUser sysUser = sysUserDao.getByDomainUserAccount(userName);
String userId = sysUser.getUserId();
AccessToken accessToken = new AccessToken();
accessToken.setType(AccessToken.TYPE_USER);

accessToken.setUserCode(userId);
accessToken.setUsername(sysUser.getUserAccount());
accessToken.setUserNick(sysUser.getUserName());
accessToken.setDeptCode(sysUser.getDeptId());
accessToken.setRoles(List.of(sysUser.getRoleId()));

accessToken.setLoginIp(Access.ip());
accessToken.setLoginTime(Access.time());
accessToken.setAccessIp(Access.ip());
accessToken.setAccessTime(Access.time());
accessToken.setId(IdUtil.fastSimpleUUID());

String token = tokenService.newToken(accessToken);
accessToken.setToken(token);
return accessToken;
}
}

4.3 判断用户是否禁用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/**
* 根据AD域的userAccountControl属性判断用户是否禁用
*
* @param userAccContr
* @return
*/
private Boolean getUserDelete(int userAccContr) {
//TRUSTED_TO_AUTH_FOR_DELEGATION - 允许该帐户进行委派
if (userAccContr >= 16777216) {
userAccContr = userAccContr - 16777216;
}
//PASSWORD_EXPIRED - (Windows 2000/Windows Server 2003) 用户的密码已过期
if (userAccContr >= 8388608) {
userAccContr = userAccContr - 8388608;
}
//DONT_REQ_PREAUTH
if (userAccContr >= 4194304) {
userAccContr = userAccContr - 4194304;
}
//USE_DES_KEY_ONLY - (Windows 2000/Windows Server 2003) 将此用户限制为仅使用数据加密标准 (DES) 加密类型的密钥
if (userAccContr >= 2097152) {
userAccContr = userAccContr - 2097152;
}
//NOT_DELEGATED - 设置此标志后,即使将服务帐户设置为信任其进行 Kerberos 委派,也不会将用户的安全上下文委派给该服务
if (userAccContr >= 1048576) {
userAccContr = userAccContr - 1048576;
}
//TRUSTED_FOR_DELEGATION - 设置此标志后,将信任运行服务的服务帐户(用户或计算机帐户)进行 Kerberos 委派。
// 任何此类服务都可模拟请求该服务的客户端。若要允许服务进行 Kerberos 委派,必须在服务帐户的 userAccountControl 属性上设置此标志
if (userAccContr >= 524288) {
userAccContr = userAccContr - 524288;
}
//SMARTCARD_REQUIRED - 设置此标志后,将强制用户使用智能卡登录
if (userAccContr >= 262144) {
userAccContr = userAccContr - 262144;
}
//MNS_LOGON_ACCOUNT - 这是 MNS 登录帐户
if (userAccContr >= 131072) {
userAccContr = userAccContr - 131072;
}
//DONT_EXPIRE_PASSWORD-密码永不过期
if (userAccContr >= 65536) {
userAccContr = userAccContr - 65536;
}
//MNS_LOGON_ACCOUNT - 这是 MNS 登录帐户
if (userAccContr >= 2097152) {
userAccContr = userAccContr - 2097152;
}
//SERVER_TRUST_ACCOUNT - 这是属于该域的域控制器的计算机帐户
if (userAccContr >= 8192) {
userAccContr = userAccContr - 8192;
}
//WORKSTATION_TRUST_ACCOUNT - 这是运行 Microsoft Windows NT 4.0 Workstation、Microsoft Windows NT 4.0 Server、
// Microsoft Windows 2000 Professional 或 Windows 2000 Server 并且属于该域的计算机的计算机帐户
if (userAccContr >= 4096) {
userAccContr = userAccContr - 4096;
}
//INTERDOMAIN_TRUST_ACCOUNT - 对于信任其他域的系统域,此属性允许信任该系统域的帐户
if (userAccContr >= 2048) {
userAccContr = userAccContr - 2048;
}
//NORMAL_ACCOUNT - 这是表示典型用户的默认帐户类型
if (userAccContr >= 512) {
userAccContr = userAccContr - 512;
}
//TEMP_DUPLICATE_ACCOUNT - 此帐户属于其主帐户位于另一个域中的用户。此帐户为用户提供访问该域的权限,
// 但不提供访问信任该域的任何域的权限。有时将这种帐户称为“本地用户帐户”
if (userAccContr >= 256) {
userAccContr = userAccContr - 256;
}
//ENCRYPTED_TEXT_PASSWORD_ALLOWED - 用户可以发送加密的密码
if (userAccContr >= 128) {
userAccContr = userAccContr - 128;
}
//PASSWD_CANT_CHANGE - 用户不能更改密码。可以读取此标志,但不能直接设置它
if (userAccContr >= 64) {
userAccContr = userAccContr - 64;
}
//PASSWD_NOTREQD - 不需要密码
if (userAccContr >= 32) {
userAccContr = userAccContr - 32;
}
//LOCKOUT
if (userAccContr >= 16) {
userAccContr = userAccContr - 16;
}
//HOMEDIR_REQUIRED - 需要主文件夹
if (userAccContr >= 8) {
userAccContr = userAccContr - 8;
}
if (userAccContr >= 2) {
return true;
}
return false;
}