Browse Source

fix:[域控对接] 接口返回添加显示名称、邮箱字段

master
yuyantian 1 month ago
parent
commit
088e28b790
2 changed files with 223 additions and 52 deletions
  1. +17
    -27
      hxhq-modules/hxhq-integration/src/main/java/com/hxhq/HxhqIntegrationApplication.java
  2. +206
    -25
      hxhq-modules/hxhq-integration/src/main/java/com/hxhq/common/ad/JdkADAuthUtil.java

+ 17
- 27
hxhq-modules/hxhq-integration/src/main/java/com/hxhq/HxhqIntegrationApplication.java View File

@ -1,5 +1,6 @@
package com.hxhq; package com.hxhq;
import com.alibaba.fastjson.JSONObject;
import com.hxhq.common.ad.ADProperties; import com.hxhq.common.ad.ADProperties;
import com.hxhq.common.ad.JdkADAuthUtil; import com.hxhq.common.ad.JdkADAuthUtil;
import com.hxhq.common.core.web.domain.AjaxResult; 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.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import java.util.Map;
/** /**
* 系统模块 * 系统模块
* *
@ -28,7 +31,7 @@ public class HxhqIntegrationApplication
System.out.println("数据对接模块启动成功"); System.out.println("数据对接模块启动成功");
// 1. 配置AD基础信息替换为你的实际配置
// 测试代码示例
ADProperties adConfig = new ADProperties(); ADProperties adConfig = new ADProperties();
adConfig.setServerHost("172.21.10.1"); adConfig.setServerHost("172.21.10.1");
adConfig.setServerPort(389); adConfig.setServerPort(389);
@ -37,33 +40,20 @@ public class HxhqIntegrationApplication
adConfig.setConnectTimeout(5000); adConfig.setConnectTimeout(5000);
adConfig.getReadOnly().setUsername("adcon"); adConfig.getReadOnly().setUsername("adcon");
adConfig.getReadOnly().setPassword("JYL@it323"); adConfig.getReadOnly().setPassword("JYL@it323");
// 2. 初始化工具类核心传入只读账号替换为你的实际只读账号/密码
//
JdkADAuthUtil adAuthUtil = new JdkADAuthUtil(adConfig); 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() ? "成功" : "失败") + " =====");
} }
} }

+ 206
- 25
hxhq-modules/hxhq-integration/src/main/java/com/hxhq/common/ad/JdkADAuthUtil.java View File

@ -9,17 +9,19 @@ import org.springframework.stereotype.Component;
import javax.naming.Context; import javax.naming.Context;
import javax.naming.NamingEnumeration; import javax.naming.NamingEnumeration;
import javax.naming.NamingException; import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls; import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult; import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext; 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化 * 纯JDK实现的AD域控核心接口Spring Bean化
* 核心功能1. 账号密码鉴权 2. 验证账号是否存在基于只读账号 * 核心功能1. 账号密码鉴权 2. 验证账号是否存在基于只读账号
* 扩展功能返回用户中文名部门信息
*/ */
@Component @Component
public class JdkADAuthUtil { public class JdkADAuthUtil {
@ -33,10 +35,17 @@ public class JdkADAuthUtil {
// ====================== dev 环境多测试账号配置 ====================== // ====================== dev 环境多测试账号配置 ======================
private static final Map<String, String> DEV_TEST_ACCOUNTS = new HashMap<>(); private static final Map<String, String> DEV_TEST_ACCOUNTS = new HashMap<>();
// 测试账号的中文名和部门信息
private static final Map<String, Map<String, String>> DEV_TEST_USER_INFO = new HashMap<>();
static { static {
DEV_TEST_ACCOUNTS.put("hxhq", "hxhq123"); DEV_TEST_ACCOUNTS.put("hxhq", "hxhq123");
// 测试账号的扩展信息
Map<String, String> 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(); String trimUser = username.trim();
if (DEV_TEST_ACCOUNTS.containsKey(trimUser) && DEV_TEST_ACCOUNTS.get(trimUser).equals(password.trim())) { if (DEV_TEST_ACCOUNTS.containsKey(trimUser) && DEV_TEST_ACCOUNTS.get(trimUser).equals(password.trim())) {
log.debug("DEV环境测试账号鉴权成功:{}", username); log.debug("DEV环境测试账号鉴权成功:{}", username);
return AjaxResult.success("账号[" + username + "]鉴权成功");
Map<String, Object> 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<String, String> env = buildLDAPEnv(username, password); Hashtable<String, String> env = buildLDAPEnv(username, password);
log.debug("开始鉴权,用户主体名:{}", env.get(Context.SECURITY_PRINCIPAL)); log.debug("开始鉴权,用户主体名:{}", env.get(Context.SECURITY_PRINCIPAL));
// 1. 先验证账号密码
ldapContext = new InitialLdapContext(env, null); ldapContext = new InitialLdapContext(env, null);
log.debug("账号[{}]鉴权成功", username);
return AjaxResult.success("账号[" + username + "]鉴权成功");
// 2. 密码验证成功后查询用户详细信息
Map<String, Object> userInfo = getUserInfo(username);
userInfo.put("message", "账号[" + username + "]鉴权成功");
log.debug("账号[{}]鉴权成功,用户信息:{}", username, userInfo);
return AjaxResult.success(userInfo);
} catch (NamingException e) { } catch (NamingException e) {
String errorMsg = e.getMessage().toLowerCase(); String errorMsg = e.getMessage().toLowerCase();
@ -108,8 +131,17 @@ public class JdkADAuthUtil {
String pureUser = trimUser.contains("@") ? trimUser.split("@")[0] : trimUser; String pureUser = trimUser.contains("@") ? trimUser.split("@")[0] : trimUser;
if (DEV_TEST_ACCOUNTS.containsKey(pureUser)) { if (DEV_TEST_ACCOUNTS.containsKey(pureUser)) {
log.debug("DEV环境测试账号存在:{}", username); log.debug("DEV环境测试账号存在:{}", username);
return AjaxResult.success("账号[" + username + "]在AD域中存在");
Map<String, Object> 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; LdapContext ldapContext = null;
@ -120,7 +152,10 @@ public class JdkADAuthUtil {
SearchControls searchControls = new SearchControls(); SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); 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); searchControls.setTimeLimit(3000);
String filter = trimUser.contains("@") String filter = trimUser.contains("@")
@ -128,10 +163,20 @@ public class JdkADAuthUtil {
: String.format("(sAMAccountName=%s)", escapeLDAPFilter(trimUser)); : String.format("(sAMAccountName=%s)", escapeLDAPFilter(trimUser));
results = ldapContext.search(adProperties.getBaseDn(), filter, searchControls); 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<String, Object> 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 { } else {
return AjaxResult.error("账号[" + username + "]在AD域中不存在"); return AjaxResult.error("账号[" + username + "]在AD域中不存在");
} }
@ -150,6 +195,69 @@ public class JdkADAuthUtil {
} }
} }
/**
* 获取用户详细信息鉴权成功后调用
*/
private Map<String, Object> getUserInfo(String username) throws NamingException {
LdapContext ldapContext = null;
NamingEnumeration<SearchResult> results = null;
try {
// 使用只读账号查询用户信息
Hashtable<String, String> 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<String, Object> 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<String, String> buildLDAPEnv(String username, String password) { private Hashtable<String, String> buildLDAPEnv(String username, String password) {
Hashtable<String, String> env = new Hashtable<>(); Hashtable<String, String> 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<SearchResult> results = null;
Map<String, Object> allAttrMap = new HashMap<>();
try {
Hashtable<String, String> 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<String> 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) { 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); // JdkADAuthUtil adAuthUtil = new JdkADAuthUtil(adConfig);
// //
// // 3. 测试账号 // // 3. 测试账号
// String existUsername = "ELNtest01"; // 存在的账号 // String existUsername = "ELNtest01"; // 存在的账号
// String nonExistUsername = "test_not_exists"; // 不存在的账号 // String nonExistUsername = "test_not_exists"; // 不存在的账号
// String testPassword = "GLPcd_28"; // 测试账号密码
// String testPassword = "Abcd1234"; // 测试账号密码
// //
// // 4. 测试接口2验证账号是否存在无需用户密码 // // 4. 测试接口2验证账号是否存在无需用户密码
// AjaxResult exists = adAuthUtil.checkAccountExists(existUsername); // AjaxResult exists = adAuthUtil.checkAccountExists(existUsername);
@ -249,8 +426,12 @@ public class JdkADAuthUtil {
// // 5. 测试接口1账号密码鉴权 // // 5. 测试接口1账号密码鉴权
// AjaxResult authSuccess = adAuthUtil.validateAccount(existUsername, testPassword); // AjaxResult authSuccess = adAuthUtil.validateAccount(existUsername, testPassword);
// System.out.println("===== 账号[" + existUsername + "]鉴权结果:" + (authSuccess.isSuccess() ? "成功" : "失败") + " ====="); // 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"); // AjaxResult authFail = adAuthUtil.validateAccount(existUsername, "wrong_password");
// System.out.println("===== 账号[" + existUsername + "]错误密码鉴权结果:" + (authFail.isSuccess() ? "成功" : "失败") + " ====="); // System.out.println("===== 账号[" + existUsername + "]错误密码鉴权结果:" + (authFail.isSuccess() ? "成功" : "失败") + " =====");
} }
} }

Loading…
Cancel
Save