LDAP登录(域账户登录)

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;
        }
    }
}

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用Java获取AD登录账户,我们可以使用LDAP(Lightweight Directory Access Protocol)协议与AD进行通信。 首先,我们需要使用JavaLDAP库来连接ADLDAP服务器。可以使用如下代码创建一个LDAP连接: ``` java import javax.naming.Context; import javax.naming.NamingEnumeration; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.LdapContext; public class ADLogin { public static void main(String[] args) { String ldapURL = "ldap://ad_domain_controller_ip:port"; String baseDN = "DC=your_domain,DC=com"; String username = "your_username"; String password = "your_password"; try { // 创建LDAP连接 LdapContext context = new InitialLdapContext(ldapEnv, null); // 创建搜索控件 SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); // 设置要搜索的属性,这里我们只搜索sAMAccountName属性 String[] returningAttributes = {"sAMAccountName"}; // 执行搜索 NamingEnumeration<SearchResult> results = context.search(baseDN, "(sAMAccountName=" + username + ")", returningAttributes, searchControls); // 获取搜索结果 if (results.hasMore()) { SearchResult searchResult = results.next(); Attributes attributes = searchResult.getAttributes(); String loginAccount = attributes.get("sAMAccountName").get().toString(); System.out.println("登录账户:" + loginAccount); } else { System.out.println("未找到登录账户"); } // 关闭LDAP连接 context.close(); } catch (Exception e) { e.printStackTrace(); } } } ``` 在上面的代码中,我们创建了一个LDAP连接并指定AD的服务器地址、名,以及要使用的用户名和密码。然后,我们执行一个搜索操作,通过用户名查找对应的登录账户属性(这里仅查找了sAMAccountName属性)。最后,我们从搜索结果中获取登录账户的值并进行输出。 需要注意的是,在执行代码之前,需要确保你已经包含了JavaLDAP库并正确地替换了相关的服务器地址、名、用户名和密码信息。 通过以上方法,我们可以使用Java来获取AD登录账户
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值