LDAP登录(域账户登录)
1.域账户目录结构示例
2.账户配置
找相关运维拿到域账户配置信息(账号,密码,ip,baseDN等配置)
3.读取配置
1.可以使用数据库存储配置信息,也可以使用配置文件,这个不是重点。本文以数据库方式获取配置,表结构如下:
CREATE TABLE `gt_ldap_config` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`company_id` bigint(20) NOT NULL COMMENT '租户id',
`archive` bigint(20) DEFAULT NULL COMMENT '删除字段,false=0=存活',
`created_user_id` bigint(20) DEFAULT NULL COMMENT '创建人',
`created_at` datetime DEFAULT NULL COMMENT '创建时间',
`updated_at` datetime DEFAULT NULL COMMENT '更新时间',
`functional_status` varchar(64) DEFAULT NULL COMMENT '功能状态:开启=OPEN;关闭=CLOSE',
`ldap_ip` varchar(64) DEFAULT NULL COMMENT 'ldap服务器ip',
`ldap_port` varchar(64) NOT NULL COMMENT '服务器端口',
`ldap_account` varchar(64) NOT NULL COMMENT '管理账户',
`ldap_password` varchar(64) NOT NULL COMMENT '管理密码',
`salt` varchar(64) DEFAULT NULL COMMENT '密码盐值',
`base_dn` varchar(64) NOT NULL COMMENT 'DN',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_company_id` (`company_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='ldap配置信息(每个系统唯一 一份)';
4.导包
5.定义ldapUser
该user类,要与自己公司配置的域中的字段对应上,比如域配置如下:
实体定义应当如下:
/**
* @author smile.zhao
* @version 1.0
* @date 2024/3/15 9:59
*/
@Data
public class LdapUser {
@ApiModelProperty("ldap中展示的英文姓氏")
private String sn;
@ApiModelProperty("ldap中展示的英文名字")
private String cn;
@ApiModelProperty(value = "ldap中展示的员工号",example = "GT01503")
private String employeeID;
@ApiModelProperty("ldap中展示的手机号码")
private String mobile;
@ApiModelProperty(value = "ldap中展示的英文名",example = "Smile")
private String givenName;
@ApiModelProperty(value = "ldap中展示的群组",example = "CN=GT-WiFi 接入权限,OU=权限群组,DC=g-town,DC=com,DC=cn")
private List<String> memberOf;
@ApiModelProperty("ldap中展示的电话号码")
private String telephoneNumber;
@ApiModelProperty("ldap中展示的邮箱")
private String mail;
@ApiModelProperty("ldap中展示的职位")
private String title;
@ApiModelProperty("对应ldap中展示的部门")
private String department;
@ApiModelProperty("对应ldap中展示的中文名字")
private String description;
@ApiModelProperty("对应ldap中展示的中文加英文名字")
private String displayName;
@ApiModelProperty("对应ldap中展示的英文名字")
private String sAMAccountName;
@ApiModelProperty(value = "对应ldap中展示的primaryGroupId",example = "513")
private String primaryGroupId;
@ApiModelProperty(value = "对应ldap中展示的manager",example = "CN=Jiahai.Qi,OU=SAAS核心组,OU=科创中心,OU=G-Town Users,DC=g-town,DC=com,DC=cn")
private String manager;
@ApiModelProperty(value = "对应ldap中展示的用户状态",example = "true")
private Boolean userStatus;
@ApiModelProperty(value = "对应ldap中展示的office信息",example = "上海A9")
private String physicalDeliveryOfficeName;
private String distinguishedName;
}
6.定义mapper
此处仅为适配自己的mapper示例,如果不清楚mapper如何定义,可百度搜其他的定义方式
@Slf4j
public class LdapUserMapper implements AttributesMapper<LdapUser> {
@Override
public LdapUser mapFromAttributes(Attributes attr) throws NamingException {
LdapUser person = new LdapUser();
if (attr.get("sn") != null) {
person.setSn((String) attr.get("sn").get());
}
if (attr.get("cn") != null) {
person.setCn((String) attr.get("cn").get());
}
if (attr.get("employeeID") != null) {
person.setEmployeeID((String) attr.get("employeeID").get());
}
if (attr.get("mobile") != null) {
person.setMobile((String) attr.get("mobile").get());
}
if (attr.get("telephoneNumber") != null) {
person.setTelephoneNumber((String) attr.get("telephoneNumber").get());
}
if (attr.get("mail") != null) {
person.setMail((String) attr.get("mail").get());
}
if (attr.get("memberOf") != null) {
List<String> list = new ArrayList();
for (Object str : Collections.list(attr.get("memberOf").getAll())) {
String ad = (String) str;
String cn = ad.substring(3, ad.indexOf(","));
list.add(cn);
}
person.setMemberOf(list);
}
if (attr.get("sAMAccountName") != null) {
person.setSAMAccountName((String) attr.get("sAMAccountName").get());
}
if (attr.get("title") != null) {
person.setTitle((String) attr.get("title").get());
}
if (attr.get("department") != null) {
person.setDepartment((String) attr.get("department").get());
}
if (attr.get("displayName") != null) {
person.setDisplayName((String) attr.get("displayName").get());
}
if (attr.get("distinguishedName") != null){
person.setDistinguishedName((String) attr.get("distinguishedName").get());
}
if (attr.get("primaryGroupID") != null) {
person.setPrimaryGroupId((String) attr.get("primaryGroupID").get());
}
if (attr.get("manager") != null) {
person.setManager((String) attr.get("manager").get());
}
if (attr.get("description") != null) {
person.setDescription((String) attr.get("description").get());
}
if (attr.get("physicalDeliveryOfficeName") != null) {
person.setPhysicalDeliveryOfficeName((String) attr.get("physicalDeliveryOfficeName").get());
}
person.setUserStatus(true);
if (attr.get("userAccountControl") != null) {
String userAccountControl = (String) attr.get("userAccountControl").get();
if("514".equals(userAccountControl) || "546".equals(userAccountControl) || "66050".equals(userAccountControl)
|| "66080".equals(userAccountControl) || "66082".equals(userAccountControl)) {
log.info(person.getCn() + " vs " + userAccountControl);
person.setUserStatus(false);
}
}
return person;
}
}
7.查询接口
/**
* 查询ldap中指定用户
*
* @param name
* @return
*/
@GetMapping("/findLdapUser")
@ApiImplicitParams({
@ApiImplicitParam(name = "name", value = "name", required = true, dataType = "string"),
})
@ApiOperation("依据名字查询ldap指定用户")
public R<LdapUser> findLdapUser(@RequestParam("name") String name, HttpServletRequest request) {
//TODO 越权校验:companyId
return ldapUserDirectory.selectLdapUser(name, request);
}
8.impl实现类
private static final String BASE = "ou=G-Town Users";
private static final String BASE_CUSTOMER_DEPART = "OU=G-Town Users 02";
private static final String ADDRESS_PREFIX = "ldap://";
@Autowired
LdapTemplate ldapTemplate;
@Autowired
GtLdapConfigMapper gtLdapConfigMapper;
@Autowired
UserMapper userMapper;
@Autowired
RedisUtil redisUtil;
@Override
public R<LdapUser> selectLdapUser(String name, HttpServletRequest request) {
String token = request.getHeader("Token");
if (StringUtils.isBlank(token)) {
return R.fail("请携带token");
}
String str = (String) redisUtil.get(token);
if (StringUtils.isBlank(str)) {
return R.fail("token过期");
}
JSONObject json = JSONObject.parseObject(str);
Long userId = Long.parseLong((String) json.get("userId"));
GtUser gtUser = userMapper.selectByPrimaryKey(userId);
if (Objects.isNull(gtUser) || Objects.isNull(gtUser.getCompanyId())) {
return R.fail("用户不存在");
}
//校验ldap链接及用户名和密码是否可用,为了避免重复链接耗费系统资源,若验证通过后,会将该租户id保存到redis中,直到下一次修改时,将此id移除并重新校验
//若redis已经记录了校验通过的配置信息,则无需再次校验
Object obj = redisUtil.get(RedisKeySplitUtil.ldapSuccessCompanyKey(gtUser.getCompanyId()));
GtLdapConfig gtLdapConfig;
if (Objects.isNull(obj)) {
gtLdapConfig = connectionVerification(gtUser.getCompanyId());
if (Objects.isNull(gtLdapConfig)) {
return R.fail("ldap链接失败");
}
} else {
gtLdapConfig = gtLdapConfigMapper.selectByCompanyId(gtUser.getCompanyId());
if (Objects.isNull(gtLdapConfig)) {
return R.fail("ldap链接失败");
}
gtLdapConfig.setLdapPassword(AesUtils.decode(gtLdapConfig.getLdapPassword()));
gtLdapConfig.setLdapConnectionUrl(ADDRESS_PREFIX + gtLdapConfig.getLdapIp() + ":" + gtLdapConfig.getLdapPort());
}
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(gtLdapConfig.getLdapConnectionUrl());
//DC=g-town,DC=com,DC=cn
contextSource.setBase(gtLdapConfig.getBaseDn());
//LDAPSAAS
contextSource.setUserDn(gtLdapConfig.getLdapAccount());
contextSource.setPassword(gtLdapConfig.getLdapPassword());
contextSource.afterPropertiesSet();
ldapTemplate = new LdapTemplate(contextSource);
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectClass", "person"));
filter.and(new EqualsFilter("sAMAccountName", name));
List<LdapUser> result = ldapTemplate.search(BASE, filter.encode(), new LdapUserMapper());
log.info("result:{}", result);
if (CollectionUtils.isEmpty(result)) {
result = ldapTemplate.search(BASE_CUSTOMER_DEPART, filter.encode(), new LdapUserMapper());
}
return result.size() > 0 ? R.success(result.get(0)) : null;
}
如此这般即可
9.具体实现类
1.由名称查用户
2.由邮箱查用户
3.由手机号查用户
4.查询所有用户
5.登录ldap
package com.gtown.colud.erp.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.gtown.cloud.erp.R;
import com.gtown.cloud.erp.config.BaseUser;
import com.gtown.cloud.erp.config.UserContext;
import com.gtown.colud.erp.Utils.RedisKeySplitUtil;
import com.gtown.colud.erp.Utils.aes.AesUtils;
import com.gtown.colud.erp.Utils.redis.RedisUtil;
import com.gtown.colud.erp.entity.GtLdapConfig;
import com.gtown.colud.erp.entity.GtUser;
import com.gtown.colud.erp.entity.LdapUser;
import com.gtown.colud.erp.mapper.GtLdapConfigMapper;
import com.gtown.colud.erp.mapper.LdapUserMapper;
import com.gtown.colud.erp.mapper.UserMapper;
import com.gtown.colud.erp.service.LdapDirectory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.query.LdapQuery;
import org.springframework.ldap.query.LdapQueryBuilder;
import org.springframework.stereotype.Service;
import javax.naming.directory.InitialDirContext;
import javax.servlet.http.HttpServletRequest;
import java.util.Hashtable;
import java.util.List;
import java.util.Objects;
/**
* @author smile.zhao
* @version 1.0
* @date 2024/3/15 11:45
*/
@Slf4j
@Service
public class LdapDirectoryImpl implements LdapDirectory {
private static final String BASE = "ou=G-Town Users";
private static final String BASE_CUSTOMER_DEPART = "OU=G-Town Users 02";
private static final String BASE_DISABLE = "ou=离职禁用账户";
private static final String BOSS_MALL="XXX@163.COM";
private static final String ADDRESS_PREFIX = "ldap://";
@Autowired
LdapTemplate ldapTemplate;
@Autowired
GtLdapConfigMapper gtLdapConfigMapper;
@Autowired
UserMapper userMapper;
@Autowired
RedisUtil redisUtil;
@Override
public R<LdapUser> selectLdapUser(String name, HttpServletRequest request) {
String token = request.getHeader("Token");
if (StringUtils.isBlank(token)) {
return R.fail("请携带token");
}
String str = (String) redisUtil.get(token);
if (StringUtils.isBlank(str)) {
return R.fail("token过期");
}
JSONObject json = JSONObject.parseObject(str);
Long userId = Long.parseLong((String) json.get("userId"));
GtUser gtUser = userMapper.selectByPrimaryKey(userId);
if (Objects.isNull(gtUser) || Objects.isNull(gtUser.getCompanyId())) {
return R.fail("用户不存在");
}
//校验ldap链接及用户名和密码是否可用,为了避免重复链接耗费系统资源,若验证通过后,会将该租户id保存到redis中,直到下一次修改时,将此id移除并重新校验
//若redis已经记录了校验通过的配置信息,则无需再次校验
Object obj = redisUtil.get(RedisKeySplitUtil.ldapSuccessCompanyKey(gtUser.getCompanyId()));
GtLdapConfig gtLdapConfig;
if (Objects.isNull(obj)) {
gtLdapConfig = connectionVerification(gtUser.getCompanyId());
if (Objects.isNull(gtLdapConfig)) {
return R.fail("ldap链接失败");
}
} else {
gtLdapConfig = gtLdapConfigMapper.selectByCompanyId(gtUser.getCompanyId());
if (Objects.isNull(gtLdapConfig)) {
return R.fail("ldap链接失败");
}
gtLdapConfig.setLdapPassword(AesUtils.decode(gtLdapConfig.getLdapPassword()));
gtLdapConfig.setLdapConnectionUrl(ADDRESS_PREFIX + gtLdapConfig.getLdapIp() + ":" + gtLdapConfig.getLdapPort());
}
LdapContextSource contextSource = new LdapContextSource();
// ldap://127.0.0.1:389
contextSource.setUrl(gtLdapConfig.getLdapConnectionUrl());
//DC=g-town,DC=com,DC=cn
contextSource.setBase(gtLdapConfig.getBaseDn());
//LDAPSAAS
contextSource.setUserDn(gtLdapConfig.getLdapAccount());
contextSource.setPassword(gtLdapConfig.getLdapPassword());
contextSource.afterPropertiesSet();
ldapTemplate = new LdapTemplate(contextSource);
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectClass", "person"));
filter.and(new EqualsFilter("sAMAccountName", name));
List<LdapUser> result = ldapTemplate.search(BASE, filter.encode(), new LdapUserMapper());
log.info("result:{}", result);
if (CollectionUtils.isEmpty(result)) {
result = ldapTemplate.search(BASE_CUSTOMER_DEPART, filter.encode(), new LdapUserMapper());
}
return result.size() > 0 ? R.success(result.get(0)) : null;
}
@Override
public LdapUser selectLdapUserByEmail(String email, Long companyId) {
//校验ldap链接及用户名和密码是否可用,为了避免重复链接耗费系统资源,若验证通过后,会将该租户id保存到redis中,直到下一次修改时,将此id移除并重新校验
//若redis已经记录了校验通过的配置信息,则无需再次校验
Object obj = redisUtil.get(RedisKeySplitUtil.ldapSuccessCompanyKey(companyId));
GtLdapConfig gtLdapConfig;
if (Objects.isNull(obj)) {
//redis未缓存ldap链接验证信息,需要验证链接是否可用
gtLdapConfig = connectionVerification(companyId);
if (Objects.isNull(gtLdapConfig)) {
log.info("ldap链接失败");
return null;
}
} else {
gtLdapConfig = gtLdapConfigMapper.selectByCompanyId(companyId);
if (Objects.isNull(gtLdapConfig)) {
log.info("ldap配置信息不存在");
return null;
}
gtLdapConfig.setLdapPassword(AesUtils.decode(gtLdapConfig.getLdapPassword()));
gtLdapConfig.setLdapConnectionUrl(ADDRESS_PREFIX + gtLdapConfig.getLdapIp() + ":" + gtLdapConfig.getLdapPort());
}
LdapContextSource contextSource = new LdapContextSource();
// ldap://127.0.0.1:389
contextSource.setUrl(gtLdapConfig.getLdapConnectionUrl());
//DC=g-town,DC=com,DC=cn
contextSource.setBase(gtLdapConfig.getBaseDn());
//LDAPSAAS
contextSource.setUserDn(gtLdapConfig.getLdapAccount());
contextSource.setPassword(gtLdapConfig.getLdapPassword());
contextSource.afterPropertiesSet();
ldapTemplate = new LdapTemplate(contextSource);
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectClass", "person"));
filter.and(new EqualsFilter("mail", email));
List<LdapUser> result = ldapTemplate.search(BASE, filter.encode(), new LdapUserMapper());
log.info("result:{}", result);
if (CollectionUtils.isEmpty(result)) {
result = ldapTemplate.search(BASE_CUSTOMER_DEPART, filter.encode(), new LdapUserMapper());
}
return result.size() > 0 ? result.get(0) : null;
}
@Override
public R selectLdapPhone(String phone, HttpServletRequest request) {
String token = request.getHeader("Token");
if (StringUtils.isBlank(token)) {
return R.fail("请携带token");
}
String str = (String) redisUtil.get(token);
if (StringUtils.isBlank(str)) {
return R.fail("token过期");
}
JSONObject json = JSONObject.parseObject(str);
Long userId = Long.parseLong((String) json.get("userId"));
GtUser gtUser = userMapper.selectByPrimaryKey(userId);
if (Objects.isNull(gtUser) || Objects.isNull(gtUser.getCompanyId())) {
return R.fail("用户不存在");
}
//校验ldap链接及用户名和密码是否可用,为了避免重复链接耗费系统资源,若验证通过后,会将该租户id保存到redis中,直到下一次修改时,将此id移除并重新校验
//若redis已经记录了校验通过的配置信息,则无需再次校验
Object obj = redisUtil.get(RedisKeySplitUtil.ldapSuccessCompanyKey(gtUser.getCompanyId()));
GtLdapConfig gtLdapConfig;
if (Objects.isNull(obj)) {
gtLdapConfig = connectionVerification(gtUser.getCompanyId());
if (Objects.isNull(gtLdapConfig)) {
return R.fail("ldap链接失败");
}
} else {
gtLdapConfig = gtLdapConfigMapper.selectByCompanyId(gtUser.getCompanyId());
if (Objects.isNull(gtLdapConfig)) {
return R.fail("ldap链接失败");
}
gtLdapConfig.setLdapPassword(AesUtils.decode(gtLdapConfig.getLdapPassword()));
gtLdapConfig.setLdapConnectionUrl(ADDRESS_PREFIX + gtLdapConfig.getLdapIp() + ":" + gtLdapConfig.getLdapPort());
}
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(gtLdapConfig.getLdapConnectionUrl());
contextSource.setBase(gtLdapConfig.getBaseDn());
contextSource.setUserDn(gtLdapConfig.getLdapAccount());
contextSource.setPassword(gtLdapConfig.getLdapPassword());
contextSource.afterPropertiesSet();
ldapTemplate = new LdapTemplate(contextSource);
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectClass", "person"));
filter.and(new EqualsFilter("telephoneNumber", phone));
List<LdapUser> result = ldapTemplate.search(BASE, filter.encode(), new LdapUserMapper());
log.info("search" + result);
if (CollectionUtils.isEmpty(result)) {
result = ldapTemplate.search(BASE_CUSTOMER_DEPART, filter.encode(), new LdapUserMapper());
}
return R.success(result);
}
@Override
public R<List<LdapUser>> findLdapAll() {
BaseUser baseUser = UserContext.get();
if (Objects.isNull(baseUser) || Objects.isNull(baseUser.getCompanyId())) {
return R.fail("用户不存在");
}
//查询配置信息表
GtLdapConfig configInfo = gtLdapConfigMapper.selectByCompanyId(baseUser.getCompanyId());
if (Objects.isNull(configInfo) || Objects.isNull(configInfo.getCompanyId()) || StringUtils.isBlank(configInfo.getLdapIp()) || StringUtils.isBlank(configInfo.getLdapAccount()) || StringUtils.isBlank(configInfo.getLdapPassword()) || StringUtils.isBlank(configInfo.getBaseDn())) {
return R.fail("ldap配置信息不存在");
}
//若redis已经记录了校验通过的配置信息,则无需再次校验
Object obj = redisUtil.get(RedisKeySplitUtil.ldapSuccessCompanyKey(configInfo.getCompanyId()));
if (Objects.isNull(obj)) {
GtLdapConfig tempConfig = connectionVerification(configInfo.getCompanyId());
if (Objects.isNull(tempConfig)) {
return R.fail("ldap链接失败");
}
}
LdapContextSource contextSource = new LdapContextSource();
// LDAP服务器地址
String ldapURL = ADDRESS_PREFIX + configInfo.getLdapIp() + ":" + configInfo.getLdapPort();
contextSource.setUrl(ldapURL);
contextSource.setBase(configInfo.getBaseDn());
contextSource.setUserDn(configInfo.getLdapAccount());
contextSource.setPassword(AesUtils.decode(configInfo.getLdapPassword()));
contextSource.afterPropertiesSet();
ldapTemplate = new LdapTemplate(contextSource);
LdapQuery query = LdapQueryBuilder.query().base(BASE).filter("(objectClass=person)");
List<LdapUser> userList = ldapTemplate.search(query, new LdapUserMapper());
log.info("LDAP服务查询结果 userList:{}", CollectionUtils.isEmpty(userList) ? "null" : userList.size());
LdapQuery queryCustomer = LdapQueryBuilder.query().base(BASE_CUSTOMER_DEPART).filter("(objectClass=person)");
List<LdapUser> customerList = ldapTemplate.search(queryCustomer, new LdapUserMapper());
log.info("LDAP服务查询结果 customerList:{}", CollectionUtils.isEmpty(customerList) ? "null" : customerList.size());
if (CollectionUtils.isNotEmpty(customerList)) {
userList.addAll(customerList);
}
return R.success(userList);
}
@Override
public R<LdapUser> findLdapUserByEmail(String mail, HttpServletRequest request) {
String token = request.getHeader("Token");
if (StringUtils.isBlank(token)) {
return R.fail("请携带token");
}
String str = (String) redisUtil.get(token);
if (StringUtils.isBlank(str)) {
return R.fail("token过期");
}
JSONObject json = JSONObject.parseObject(str);
Long userId = Long.parseLong((String) json.get("userId"));
GtUser gtUser = userMapper.selectByPrimaryKey(userId);
if (Objects.isNull(gtUser) || Objects.isNull(gtUser.getCompanyId())) {
return R.fail("用户不存在");
}
//校验ldap链接及用户名和密码是否可用,为了避免重复链接耗费系统资源,若验证通过后,会将该租户id保存到redis中,直到下一次修改时,将此id移除并重新校验
//若redis已经记录了校验通过的配置信息,则无需再次校验
Object obj = redisUtil.get(RedisKeySplitUtil.ldapSuccessCompanyKey(gtUser.getCompanyId()));
GtLdapConfig gtLdapConfig;
if (Objects.isNull(obj)) {
gtLdapConfig = connectionVerification(gtUser.getCompanyId());
if (Objects.isNull(gtLdapConfig)) {
return R.fail("ldap链接失败");
}
} else {
gtLdapConfig = gtLdapConfigMapper.selectByCompanyId(gtUser.getCompanyId());
if (Objects.isNull(gtLdapConfig)) {
return R.fail("ldap链接失败");
}
gtLdapConfig.setLdapPassword(AesUtils.decode(gtLdapConfig.getLdapPassword()));
gtLdapConfig.setLdapConnectionUrl(ADDRESS_PREFIX + gtLdapConfig.getLdapIp() + ":" + gtLdapConfig.getLdapPort());
}
LdapContextSource contextSource = new LdapContextSource();
// ldap://127.0.0.1:389
contextSource.setUrl(gtLdapConfig.getLdapConnectionUrl());
//DC=g-town,DC=com,DC=cn
contextSource.setBase(gtLdapConfig.getBaseDn());
//LDAPSAAS
contextSource.setUserDn(gtLdapConfig.getLdapAccount());
contextSource.setPassword(gtLdapConfig.getLdapPassword());
contextSource.afterPropertiesSet();
ldapTemplate = new LdapTemplate(contextSource);
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectClass", "person"));
filter.and(new EqualsFilter("mail", mail));
List<LdapUser> result = ldapTemplate.search(BASE, filter.encode(), new LdapUserMapper());
if (CollectionUtils.isEmpty(result)) {
result = ldapTemplate.search(BASE_CUSTOMER_DEPART, filter.encode(), new LdapUserMapper());
}
log.info("result:{}", result);
return result.size() > 0 ? R.success(result.get(0)) : null;
}
/**
* 登录ldap
* TODO 前提:ldap配置信息表中有且仅能有一条数据,若多家公司公用同一个数据库,此处无法区分当前登录用户属于哪个公司,需传入companyId方可使用
*
* @param name
* @param password
* @param userByAccount
* @return
*/
@Override
public R<LdapUser> loginLdap(String name, String password, GtUser userByAccount) {
BaseUser baseUser = UserContext.get();
if (Objects.isNull(baseUser) || Objects.isNull(baseUser.getCompanyId())) {
log.info("baseUser:{}", baseUser);
return R.fail("用户CompanyId不存在");
}
log.info("baseUser:{}", baseUser);
GtLdapConfig configInfo = gtLdapConfigMapper.selectByCompanyId(baseUser.getCompanyId());
log.info("configInfo:{}", configInfo);
if (Objects.isNull(configInfo) || Objects.isNull(configInfo.getCompanyId()) ||
StringUtils.isBlank(configInfo.getLdapPassword()) || StringUtils.isBlank(configInfo.getLdapIp()) || StringUtils.isBlank(configInfo.getLdapPort())) {
log.error("ldap未配置");
return R.fail(Objects.isNull(userByAccount) ? "账户不存在" : "密码错误");
}
//校验ldap链接及用户名和密码是否可用
//若redis已经记录了校验通过的配置信息,则无需再次校验
Object obj = redisUtil.get(RedisKeySplitUtil.ldapSuccessCompanyKey(configInfo.getCompanyId()));
log.info("Redis查询结果:{}", obj);
if (Objects.isNull(obj)) {
GtLdapConfig tempConfig = connectionVerification(configInfo.getCompanyId());
if (Objects.isNull(tempConfig)) {
log.error("ldap链接失败");
return R.fail(Objects.isNull(userByAccount) ? "账户不存在" : "密码错误");
}
}
log.info("ldap链接成功:dn:{}", configInfo.getBaseDn());
configInfo.setLdapPassword(AesUtils.decode(configInfo.getLdapPassword()));
configInfo.setLdapConnectionUrl(ADDRESS_PREFIX + configInfo.getLdapIp() + ":" + configInfo.getLdapPort());
LdapContextSource contextSource = new LdapContextSource();
// ldap://127.0.0.1:389
contextSource.setUrl(configInfo.getLdapConnectionUrl());
//DC=g-town,DC=com,DC=cn
contextSource.setBase(configInfo.getBaseDn());
//LDAPSAAS
contextSource.setUserDn(configInfo.getLdapAccount());
contextSource.setPassword(configInfo.getLdapPassword());
contextSource.afterPropertiesSet();
ldapTemplate = new LdapTemplate(contextSource);
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectClass", "person"));
filter.and(new EqualsFilter("sAMAccountName", name));
List<LdapUser> result = ldapTemplate.search(BASE, filter.encode(), new LdapUserMapper());
log.info("LDAP服务查询结果 result:{}", result);
if (CollectionUtils.isEmpty(result)) {
log.error(BASE + "查询用户" + name + "不存在");
result = ldapTemplate.search(BASE_CUSTOMER_DEPART, filter.encode(), new LdapUserMapper());
if (CollectionUtils.isEmpty(result)) {
log.error(BASE_CUSTOMER_DEPART + "查询用户" + name + "不存在");
return R.fail(Objects.isNull(userByAccount) ? "账户不存在" : "密码错误");
}
}
userByAccount = new GtUser().setAccount(name);
boolean authenticate = ldapTemplate.authenticate(BASE, "(sAMAccountName=" + name + ")", password);
if (!authenticate) {
authenticate = ldapTemplate.authenticate(BASE_CUSTOMER_DEPART, "(sAMAccountName=" + name + ")", password);
}
if (authenticate) {
return R.success(result.get(0));
}
log.info("ldap登录失败");
return R.fail(Objects.isNull(userByAccount) ? "账户不存在" : "密码错误");
}
@Override
public R<List<LdapUser>> findLdapAll(GtLdapConfig configInfo) {
//若redis已经记录了校验通过的配置信息,则无需再次校验
Object obj = redisUtil.get(RedisKeySplitUtil.ldapSuccessCompanyKey(configInfo.getCompanyId()));
if (Objects.isNull(obj)) {
GtLdapConfig tempConfig = connectionVerification(configInfo.getCompanyId());
if (Objects.isNull(tempConfig)) {
return R.fail("ldap链接失败");
}
}
LdapContextSource contextSource = new LdapContextSource();
// LDAP服务器地址
String ldapURL = ADDRESS_PREFIX + configInfo.getLdapIp() + ":" + configInfo.getLdapPort();
contextSource.setUrl(ldapURL);
contextSource.setBase(configInfo.getBaseDn());
contextSource.setUserDn(configInfo.getLdapAccount());
contextSource.setPassword(AesUtils.decode(configInfo.getLdapPassword()));
contextSource.afterPropertiesSet();
ldapTemplate = new LdapTemplate(contextSource);
LdapQuery query = LdapQueryBuilder.query().base(BASE).filter("(objectClass=person)");
List<LdapUser> userList = ldapTemplate.search(query, new LdapUserMapper());
log.info("LDAP服务查询结果 userList:{}", CollectionUtils.isEmpty(userList) ? "null" : userList.size());
LdapQuery customerQuery = LdapQueryBuilder.query().base(BASE_CUSTOMER_DEPART).filter("(objectClass=person)");
List<LdapUser> customerList = ldapTemplate.search(customerQuery, new LdapUserMapper());
log.info("LDAP服务查询结果 customerList:{}", CollectionUtils.isEmpty(customerList) ? "null" : customerList.size());
if (CollectionUtils.isNotEmpty(customerList)) {
userList.addAll(customerList);
}
return R.success(userList);
}
public GtLdapConfig connectionVerification(Long companyId) {
GtLdapConfig config = gtLdapConfigMapper.selectByCompanyId(companyId);
if (Objects.isNull(config)) {
log.info("未找到ldap配置信息");
return null;
}
String ldapIp = config.getLdapIp();
String ldapPort = config.getLdapPort();
String ldapAccount = config.getLdapAccount();
String ldapPassword = config.getLdapPassword();
if (StringUtils.isBlank(ldapIp) || StringUtils.isBlank(ldapPort) || StringUtils.isBlank(ldapAccount) || StringUtils.isBlank(ldapPassword)) {
log.info("ldap配置信息不完整");
return null;
}
//密码需要解密
ldapPassword = AesUtils.decode(config.getLdapPassword());
// LDAP服务器地址
String ldapURL = ADDRESS_PREFIX + ldapIp + ":" + ldapPort;
// 安全认证信息
Hashtable<String, String> env = new Hashtable<>();
env.put(InitialDirContext.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(InitialDirContext.PROVIDER_URL, ldapURL);
// 或者"simple"、"none"
env.put(InitialDirContext.SECURITY_AUTHENTICATION, "simple");
//管理员用户名
env.put(InitialDirContext.SECURITY_PRINCIPAL, ldapAccount);
//管理员密码
env.put(InitialDirContext.SECURITY_CREDENTIALS, ldapPassword);
try {
// 创建初始DirContext对象进行连接
InitialDirContext initialDirContext = new InitialDirContext(env);
// 如果连接成功,关闭连接
initialDirContext.close();
config.setLdapConnectionUrl(ldapURL);
config.setLdapPassword(ldapPassword);
String ldapKey = RedisKeySplitUtil.ldapSuccessCompanyKey(companyId);
redisUtil.set(ldapKey, companyId, RedisKeySplitUtil.LDAP_EXPIRE_TIME);
return config;
} catch (Exception e) {
log.error("ldap连接失败");
return null;
}
}
}