diff --git a/hxhq-modules/hxhq-integration/src/main/java/com/hxhq/HxhqIntegrationApplication.java b/hxhq-modules/hxhq-integration/src/main/java/com/hxhq/HxhqIntegrationApplication.java index 8e1ce26..c173c8b 100644 --- a/hxhq-modules/hxhq-integration/src/main/java/com/hxhq/HxhqIntegrationApplication.java +++ b/hxhq-modules/hxhq-integration/src/main/java/com/hxhq/HxhqIntegrationApplication.java @@ -1,5 +1,6 @@ package com.hxhq; +import com.alibaba.fastjson.JSONObject; import com.hxhq.common.ad.ADProperties; import com.hxhq.common.ad.JdkADAuthUtil; import com.hxhq.common.core.web.domain.AjaxResult; @@ -11,6 +12,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ComponentScan; +import java.util.Map; + /** * 系统模块 * @@ -28,7 +31,7 @@ public class HxhqIntegrationApplication System.out.println("数据对接模块启动成功"); - // 1. 配置AD基础信息(替换为你的实际配置) + // 测试代码示例 ADProperties adConfig = new ADProperties(); adConfig.setServerHost("172.21.10.1"); adConfig.setServerPort(389); @@ -37,33 +40,20 @@ public class HxhqIntegrationApplication adConfig.setConnectTimeout(5000); adConfig.getReadOnly().setUsername("adcon"); adConfig.getReadOnly().setPassword("JYL@it323"); - - // 2. 初始化工具类(★核心★:传入只读账号,替换为你的实际只读账号/密码) +// JdkADAuthUtil adAuthUtil = new JdkADAuthUtil(adConfig); +// AjaxResult elNtest01 = adAuthUtil.getUserAllAttributes("xiaokaiwei"); +// System.out.println("用户信息:" + JSONObject.toJSONString(elNtest01)); +// +// + // 测试账号存在查询(返回用户信息) + AjaxResult existsResult = adAuthUtil.checkAccountExists("xiaokaiwei"); + System.out.println("账号存在查询结果:" + JSONObject.toJSONString(existsResult)); +// +// +// // 测试鉴权(返回用户信息) + AjaxResult authResult = adAuthUtil.validateAccount("xiaokaiwei", "Wxk1008611"); + System.out.println("鉴权结果:" + JSONObject.toJSONString(authResult)); - // 3. 测试账号 - String existUsername = "ELNtest01"; // 存在的账号 - String nonExistUsername = "test_not_exists"; // 不存在的账号 - String testPassword = "Abcd1234"; // 测试账号密码 - - // 4. 测试接口2:验证账号是否存在(无需用户密码) - AjaxResult exists = adAuthUtil.checkAccountExists(existUsername); - System.out.println("===== 验证账号[" + existUsername + "]是否存在:" + (exists.isSuccess() ? "存在" : "不存在") + " ====="); - - AjaxResult exists1 = adAuthUtil.checkAccountExists("ELNtest01@glpcd.com"); - System.out.println("===== 验证账号[" + existUsername + "]是否存在:" + (exists1.isSuccess()? "存在" : "不存在") + " ====="); - - AjaxResult nonExists = adAuthUtil.checkAccountExists(nonExistUsername); - System.out.println("===== 验证账号[" + nonExistUsername + "]是否存在:" + (nonExists.isSuccess() ? "存在" : "不存在") + " ====="); - - // 5. 测试接口1:账号密码鉴权 - AjaxResult authSuccess = adAuthUtil.validateAccount(existUsername, testPassword); - System.out.println("===== 账号[" + existUsername + "]鉴权结果:" + (authSuccess.isSuccess() ? "成功" : "失败") + " ====="); - AjaxResult authSuccess1 = adAuthUtil.validateAccount(existUsername+"@glpcd.com", testPassword); - System.out.println("===== 账号[" + existUsername + "]鉴权结果:" + (authSuccess1.isSuccess() ? "成功" : "失败") + " ====="); - - - AjaxResult authFail = adAuthUtil.validateAccount(existUsername, "wrong_password"); - System.out.println("===== 账号[" + existUsername + "]错误密码鉴权结果:" + (authFail.isSuccess() ? "成功" : "失败") + " ====="); } } diff --git a/hxhq-modules/hxhq-integration/src/main/java/com/hxhq/common/ad/JdkADAuthUtil.java b/hxhq-modules/hxhq-integration/src/main/java/com/hxhq/common/ad/JdkADAuthUtil.java index d70b244..2a33a1c 100644 --- a/hxhq-modules/hxhq-integration/src/main/java/com/hxhq/common/ad/JdkADAuthUtil.java +++ b/hxhq-modules/hxhq-integration/src/main/java/com/hxhq/common/ad/JdkADAuthUtil.java @@ -9,17 +9,19 @@ import org.springframework.stereotype.Component; import javax.naming.Context; import javax.naming.NamingEnumeration; import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.LdapContext; -import java.util.Hashtable; -import java.util.HashMap; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; /** * 纯JDK实现的AD域控核心接口(Spring Bean化) * 核心功能:1. 账号密码鉴权 2. 验证账号是否存在(基于只读账号) + * 扩展功能:返回用户中文名、部门信息 */ @Component public class JdkADAuthUtil { @@ -33,10 +35,17 @@ public class JdkADAuthUtil { // ====================== dev 环境多测试账号配置 ====================== private static final Map DEV_TEST_ACCOUNTS = new HashMap<>(); + // 测试账号的中文名和部门信息 + private static final Map> DEV_TEST_USER_INFO = new HashMap<>(); static { - DEV_TEST_ACCOUNTS.put("hxhq", "hxhq123"); + + // 测试账号的扩展信息 + Map hxhqInfo = new HashMap<>(); + hxhqInfo.put("displayName", "测试用户"); + hxhqInfo.put("mail", "hxhq@glpcd.com"); + DEV_TEST_USER_INFO.put("hxhq", hxhqInfo); } /** @@ -60,7 +69,15 @@ public class JdkADAuthUtil { String trimUser = username.trim(); if (DEV_TEST_ACCOUNTS.containsKey(trimUser) && DEV_TEST_ACCOUNTS.get(trimUser).equals(password.trim())) { log.debug("DEV环境测试账号鉴权成功:{}", username); - return AjaxResult.success("账号[" + username + "]鉴权成功"); + Map result = new HashMap<>(); + result.put("username", trimUser); + result.put("displayName", DEV_TEST_USER_INFO.get(trimUser).get("displayName")); + result.put("mail", DEV_TEST_USER_INFO.get(trimUser).get("mail")); + result.put("message", "账号[" + username + "]鉴权成功"); + return AjaxResult.success(result); + }else { + log.debug("DEV环境测试账号鉴权失败:{}", username); + return AjaxResult.error("账号[" + username + "]鉴权失败"); } } @@ -69,9 +86,15 @@ public class JdkADAuthUtil { Hashtable env = buildLDAPEnv(username, password); log.debug("开始鉴权,用户主体名:{}", env.get(Context.SECURITY_PRINCIPAL)); + // 1. 先验证账号密码 ldapContext = new InitialLdapContext(env, null); - log.debug("账号[{}]鉴权成功", username); - return AjaxResult.success("账号[" + username + "]鉴权成功"); + + // 2. 密码验证成功后,查询用户详细信息 + Map userInfo = getUserInfo(username); + userInfo.put("message", "账号[" + username + "]鉴权成功"); + + log.debug("账号[{}]鉴权成功,用户信息:{}", username, userInfo); + return AjaxResult.success(userInfo); } catch (NamingException e) { String errorMsg = e.getMessage().toLowerCase(); @@ -108,8 +131,17 @@ public class JdkADAuthUtil { String pureUser = trimUser.contains("@") ? trimUser.split("@")[0] : trimUser; if (DEV_TEST_ACCOUNTS.containsKey(pureUser)) { log.debug("DEV环境测试账号存在:{}", username); - return AjaxResult.success("账号[" + username + "]在AD域中存在"); + Map result = new HashMap<>(); + result.put("username", pureUser); + result.put("displayName", DEV_TEST_USER_INFO.get(pureUser).get("displayName")); + result.put("mail", DEV_TEST_USER_INFO.get(pureUser).get("mail")); + result.put("message", "账号[" + username + "]在AD域中存在"); + return AjaxResult.success(result); + }else { + return AjaxResult.error("账号[" + username + "]在AD域中不存在"); + } + } LdapContext ldapContext = null; @@ -120,7 +152,10 @@ public class JdkADAuthUtil { SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); - searchControls.setReturningAttributes(new String[]{"sAMAccountName", "userPrincipalName"}); + // 扩展返回属性:增加cn(中文名)、department(部门)、displayName(显示名) + searchControls.setReturningAttributes(new String[]{ + "sAMAccountName", "userPrincipalName", "cn", "department", "displayName", "mail" + }); searchControls.setTimeLimit(3000); String filter = trimUser.contains("@") @@ -128,10 +163,20 @@ public class JdkADAuthUtil { : String.format("(sAMAccountName=%s)", escapeLDAPFilter(trimUser)); results = ldapContext.search(adProperties.getBaseDn(), filter, searchControls); - boolean exists = results != null && results.hasMoreElements(); - if (exists) { - return AjaxResult.success("账号[" + username + "]在AD域中存在"); + if (results != null && results.hasMoreElements()) { + SearchResult result = results.nextElement(); + Attributes attrs = result.getAttributes(); + + // 封装用户信息 + Map userInfo = new HashMap<>(); + userInfo.put("username", trimUser); + userInfo.put("displayName", getAttributeValue(attrs, "displayName")); + userInfo.put("mail", getAttributeValue(attrs, "mail")); + + userInfo.put("message", "账号[" + username + "]在AD域中存在"); + + return AjaxResult.success(userInfo); } else { return AjaxResult.error("账号[" + username + "]在AD域中不存在"); } @@ -150,6 +195,69 @@ public class JdkADAuthUtil { } } + /** + * 获取用户详细信息(鉴权成功后调用) + */ + private Map getUserInfo(String username) throws NamingException { + LdapContext ldapContext = null; + NamingEnumeration results = null; + + try { + // 使用只读账号查询用户信息 + Hashtable env = buildLDAPEnvForQuery(); + ldapContext = new InitialLdapContext(env, null); + + SearchControls searchControls = new SearchControls(); + searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); + searchControls.setReturningAttributes(new String[]{ + "sAMAccountName", "cn", "department", "displayName", "mail", + }); + searchControls.setTimeLimit(3000); + + String filter = username.contains("@") + ? String.format("(userPrincipalName=%s)", escapeLDAPFilter(username)) + : String.format("(sAMAccountName=%s)", escapeLDAPFilter(username)); + + results = ldapContext.search(adProperties.getBaseDn(), filter, searchControls); + + Map userInfo = new HashMap<>(); + userInfo.put("username", username); + + if (results != null && results.hasMoreElements()) { + SearchResult result = results.nextElement(); + Attributes attrs = result.getAttributes(); + userInfo.put("displayName", getAttributeValue(attrs, "displayName")); + userInfo.put("mail", getAttributeValue(attrs, "mail")); + } + + return userInfo; + } finally { + closeNamingEnumeration(results); + closeLdapContext(ldapContext); + } + } + + /** + * 安全获取AD属性值(处理空值) + */ + private String getAttributeValue(Attributes attrs, String attrName) { + if (attrs == null) { + return ""; + } + + Attribute attr = attrs.get(attrName); + if (attr == null) { + return ""; + } + + try { + return attr.get() != null ? attr.get().toString() : ""; + } catch (NamingException e) { + log.warn("获取属性[{}]失败", attrName, e); + return ""; + } + } + // ====================== 以下是原有工具方法,完全不变 ====================== private Hashtable buildLDAPEnv(String username, String password) { Hashtable env = new Hashtable<>(); @@ -216,25 +324,94 @@ public class JdkADAuthUtil { } } + + /** + * 查询AD用户【所有属性】,返回完整Map,用于查看该用户到底有哪些字段 + */ + public AjaxResult getUserAllAttributes(String username) { + if (username == null || username.trim().isEmpty()) { + return AjaxResult.error("用户名不能为空"); + } + + String trimUser = username.trim(); + + LdapContext ldapContext = null; + NamingEnumeration results = null; + Map allAttrMap = new HashMap<>(); + + try { + Hashtable env = buildLDAPEnvForQuery(); + ldapContext = new InitialLdapContext(env, null); + + SearchControls searchControls = new SearchControls(); + searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); + // 【关键】返回 *所有* 属性,不指定字段 + searchControls.setReturningAttributes(null); + searchControls.setTimeLimit(5000); + + String filter = trimUser.contains("@") + ? String.format("(userPrincipalName=%s)", escapeLDAPFilter(trimUser)) + : String.format("(sAMAccountName=%s)", escapeLDAPFilter(trimUser)); + + results = ldapContext.search(adProperties.getBaseDn(), filter, searchControls); + + if (results != null && results.hasMoreElements()) { + SearchResult searchResult = results.next(); + Attributes attributes = searchResult.getAttributes(); + + // 遍历所有属性 + NamingEnumeration ids = attributes.getIDs(); + while (ids.hasMoreElements()) { + String id = ids.next(); + Attribute attr = attributes.get(id); + if (attr == null) { + allAttrMap.put(id, null); + continue; + } + try { + // 单个值 + Object value = attr.get(); + allAttrMap.put(id, value != null ? value.toString() : null); + } catch (Exception e) { + // 多值属性(如memberOf) + try { + NamingEnumeration ne = attr.getAll(); + StringBuilder sb = new StringBuilder(); + while (ne.hasMoreElements()) { + sb.append(ne.next()).append("; "); + } + allAttrMap.put(id, sb.toString()); + } catch (Exception ex) { + allAttrMap.put(id, "无法解析"); + } + } + } + + log.info("AD用户[{}]所有属性:{}", username, allAttrMap); + return AjaxResult.success("获取成功", allAttrMap); + } else { + return AjaxResult.error("用户不存在"); + } + + } catch (Exception e) { + log.error("获取用户所有属性异常", e); + return AjaxResult.error("获取失败:" + e.getMessage()); + } finally { + closeNamingEnumeration(results); + closeLdapContext(ldapContext); + } + } + + public static void main(String[] args) { -// -// // 1. 配置AD基础信息(替换为你的实际配置) -// ADProperties adConfig = new ADProperties(); -// adConfig.setServerHost("172.21.10.1"); -// adConfig.setServerPort(389); -// adConfig.setBaseDn("DC=glpcd,DC=com"); -// adConfig.setUseSsl(false); -// adConfig.setConnectTimeout(5000); -// adConfig.getReadOnly().setUsername("adcon"); -// adConfig.getReadOnly().setPassword("JYL@it323"); -// -// // 2. 初始化工具类(★核心★:传入只读账号,替换为你的实际只读账号/密码) + + // // 2. 初始化工具类(★核心★:传入只读账号,替换为你的实际只读账号/密码) // JdkADAuthUtil adAuthUtil = new JdkADAuthUtil(adConfig); // // // 3. 测试账号 // String existUsername = "ELNtest01"; // 存在的账号 // String nonExistUsername = "test_not_exists"; // 不存在的账号 -// String testPassword = "GLPcd_28"; // 测试账号密码 +// String testPassword = "Abcd1234"; // 测试账号密码 // // // 4. 测试接口2:验证账号是否存在(无需用户密码) // AjaxResult exists = adAuthUtil.checkAccountExists(existUsername); @@ -249,8 +426,12 @@ public class JdkADAuthUtil { // // 5. 测试接口1:账号密码鉴权 // AjaxResult authSuccess = adAuthUtil.validateAccount(existUsername, testPassword); // System.out.println("===== 账号[" + existUsername + "]鉴权结果:" + (authSuccess.isSuccess() ? "成功" : "失败") + " ====="); +// AjaxResult authSuccess1 = adAuthUtil.validateAccount(existUsername+"@glpcd.com", testPassword); +// System.out.println("===== 账号[" + existUsername + "]鉴权结果:" + (authSuccess1.isSuccess() ? "成功" : "失败") + " ====="); +// // // AjaxResult authFail = adAuthUtil.validateAccount(existUsername, "wrong_password"); // System.out.println("===== 账号[" + existUsername + "]错误密码鉴权结果:" + (authFail.isSuccess() ? "成功" : "失败") + " ====="); + } } \ No newline at end of file