From 6541c3a1918478fa7f5ce7f8172893fc753afb45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E4=B9=A6=E7=A7=91=E6=8A=80?= <412656+myteng@user.noreply.gitee.com> Date: Thu, 4 Jul 2024 08:55:21 +0000 Subject: [PATCH] =?UTF-8?q?!9=20LDAP=E5=90=8C=E6=AD=A5=E4=BC=98=E5=8C=96?= =?UTF-8?q?=20-=20=E4=BC=98=E5=8C=96:[API]LDAP=E7=9A=84=E9=83=A8=E9=97=A8?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E9=80=BB=E8=BE=91=20-=20=E4=BC=98=E5=8C=96:[?= =?UTF-8?q?API]LDAP=E7=9A=84=E7=94=A8=E6=88=B7=E5=90=8C=E6=AD=A5=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 29 ++-- .../java/xyz/playedu/api/bus/LoginBus.java | 3 + .../controller/frontend/LoginController.java | 9 +- .../java/xyz/playedu/common/bus/LDAPBus.java | 139 +++++++++++++----- .../common/service/LdapDepartmentService.java | 2 + .../impl/LdapDepartmentServiceImpl.java | 8 + .../playedu/common/util/ldap/LdapUtil.java | 49 +++--- 7 files changed, 162 insertions(+), 77 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae7f66d..deded14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,18 @@ -## v1.7 版本更新 +## 1.8 版本更新 -- 新增:[API]MinIO配置信息增加环境变量的读取 -- 新增:[API]学员学习权限优化 -- 新增:[后台]后台首页增加课件数量的显示 -- 新增:[后台]线上课列表增加创建人字段 -- 优化:[后台]学员部门包含子部门所有学员数量 -- 优化:[API]根据分类ID获取所有子分类的课程 -- 优化:[API]根据部门ID获取所有父级部门的课程 -- 优化:[后台]部门指派器 -- 优化:[PC]视频播放器去除右键点击 -- 优化:[PC]首页学习时长去掉秒 -- 优化:[H5]首页tab切换优化 \ No newline at end of file +- 优化:[API]LDAP的部门同步逻辑 +- 优化:[API]LDAP的用户同步逻辑 + +## 1.7 版本更新 + +- 新增:[API]MinIO配置信息增加环境变量的读取 +- 新增:[API]学员学习权限优化 +- 新增:[后台]后台首页增加课件数量的显示 +- 新增:[后台]线上课列表增加创建人字段 +- 优化:[后台]学员部门包含子部门所有学员数量 +- 优化:[API]根据分类ID获取所有子分类的课程 +- 优化:[API]根据部门ID获取所有父级部门的课程 +- 优化:[后台]部门指派器 +- 优化:[PC]视频播放器去除右键点击 +- 优化:[PC]首页学习时长去掉秒 +- 优化:[H5]首页tab切换优化 \ No newline at end of file diff --git a/playedu-api/playedu-api/src/main/java/xyz/playedu/api/bus/LoginBus.java b/playedu-api/playedu-api/src/main/java/xyz/playedu/api/bus/LoginBus.java index c0566c2..1460c4c 100644 --- a/playedu-api/playedu-api/src/main/java/xyz/playedu/api/bus/LoginBus.java +++ b/playedu-api/playedu-api/src/main/java/xyz/playedu/api/bus/LoginBus.java @@ -67,6 +67,9 @@ public class LoginBus { public HashMap tokenByLdapTransformUser(LdapTransformUser ldapTransformUser) throws ServiceException { User user = ldapBus.singleUserSync(ldapTransformUser, appConfigService.defaultAvatar()); + if (user == null) { + throw new ServiceException("用户状态异常,无法登录!"); + } return tokenByUser(user); } } diff --git a/playedu-api/playedu-api/src/main/java/xyz/playedu/api/controller/frontend/LoginController.java b/playedu-api/playedu-api/src/main/java/xyz/playedu/api/controller/frontend/LoginController.java index 9632873..8eb25a5 100644 --- a/playedu-api/playedu-api/src/main/java/xyz/playedu/api/controller/frontend/LoginController.java +++ b/playedu-api/playedu-api/src/main/java/xyz/playedu/api/controller/frontend/LoginController.java @@ -119,14 +119,7 @@ public class LoginController { try { LdapTransformUser ldapTransformUser = - LdapUtil.loginByMailOrUid( - ldapConfig.getUrl(), - ldapConfig.getAdminUser(), - ldapConfig.getAdminPass(), - ldapConfig.getBaseDN(), - mail, - uid, - req.getPassword()); + LdapUtil.loginByMailOrUid(ldapConfig, mail, uid, req.getPassword()); if (ldapTransformUser == null) { return JsonResponse.error("登录失败.请检查账号和密码"); } diff --git a/playedu-api/playedu-common/src/main/java/xyz/playedu/common/bus/LDAPBus.java b/playedu-api/playedu-common/src/main/java/xyz/playedu/common/bus/LDAPBus.java index c3acb85..dac38c5 100644 --- a/playedu-api/playedu-common/src/main/java/xyz/playedu/common/bus/LDAPBus.java +++ b/playedu-api/playedu-common/src/main/java/xyz/playedu/common/bus/LDAPBus.java @@ -28,7 +28,6 @@ import xyz.playedu.common.exception.NotFoundException; import xyz.playedu.common.service.*; import xyz.playedu.common.types.LdapConfig; import xyz.playedu.common.util.HelperUtil; -import xyz.playedu.common.util.StringUtil; import xyz.playedu.common.util.ldap.LdapTransformDepartment; import xyz.playedu.common.util.ldap.LdapTransformUser; import xyz.playedu.common.util.ldap.LdapUtil; @@ -63,11 +62,7 @@ public class LDAPBus { LdapConfig ldapConfig = appConfigService.ldapConfig(); List ouList = - LdapUtil.departments( - ldapConfig.getUrl(), - ldapConfig.getAdminUser(), - ldapConfig.getAdminPass(), - ldapConfig.getBaseDN()); + LdapUtil.departments(ldapConfig, ldapConfig.getBaseDN()); if (ouList == null || ouList.isEmpty()) { return; @@ -80,6 +75,7 @@ public class LDAPBus { // 本地缓存表 HashMap depIdKeyByName = new HashMap<>(); + // 全局排序计数 Integer sort = 0; @@ -90,20 +86,25 @@ public class LDAPBus { String[] tmpChains = dn.replace("ou=", "").split(","); String prevName = ""; + log.info("#####START#####[dn:{},uuid:{}]", dn, uuid); + // 同步记录 LdapDepartment tmpLdapDepartment = ldapDepartments.get(uuid); if (tmpLdapDepartment != null && tmpLdapDepartment.getDn().equals(dn)) { // 当前部门已经同步 && 未发生改变 + log.info("LDAP-部门同步处理-未发生改变|dn:{}", dn); continue; } // 执行到这里的有两种情况: // 1.部门未同步 // 2.部门已同步,但是发生了变化 - // 2.1 部门名称修改 - // 2.2 部门上级修改 + // |-2.1 部门名称修改 + // |-2.2 部门上级名称修改 + // |-2.3 层级发生变动(增加层级|减少层级) int length = tmpChains.length; + for (int i = 0; i < length; i++) { sort++; int parentId = 0; @@ -118,34 +119,73 @@ public class LDAPBus { parentId = depIdKeyByName.get(prevName); } - // 最后一个记录 && 已存在部门-发生了变动 + log.info( + "LDAP-部门同步处理-链处理|ctx=[dn={},fullName:{},tmpName:{},parentId:{},sort:{}]", + dn, + fullName, + tmpName, + parentId, + sort); + if (i + 1 == length && tmpLdapDepartment != null) { + // OU链发生了改变 + // 1.部门名改变 + // 2.上级部门名改变 + // 3.层级改变 + + log.info("LDAP-部门同步处理-OU链发生改变|ctx=[新:{},旧:{}]", dn, tmpLdapDepartment.getDn()); + Department tmpDepartment = departmentService.findOrFail(tmpLdapDepartment.getDepartmentId()); - departmentService.update(tmpDepartment, tmpName, parentId, sort); + if (!tmpDepartment.getName().equals(tmpName) + || tmpLdapDepartment.getDn().split(",").length + != dn.split(",").length) { + departmentService.update(tmpDepartment, tmpName, parentId, sort); + } + + // 更新同步记录 + tmpLdapDepartment.setDn(dn); // 最新的DN + ldapDepartmentService.updateDnById(tmpLdapDepartment.getId(), dn); + // 更新本地缓存 + ldapDepartments.put(uuid, tmpLdapDepartment); + // 更新本地缓存 + depIdKeyByName.put(fullName, tmpDepartment.getId()); } else { // 检查本地是否有缓存 Integer depId = depIdKeyByName.get(fullName); + log.info("LDAP-部门同步处理-从缓存查询depId|ctx=[fullName:{},depId:{}]", fullName, depId); if (depId == null) { Department tmpDep = departmentService.findByName(tmpName, parentId); if (tmpDep != null) { depId = tmpDep.getId(); + log.info( + "LDAP-部门同步处理-从数据库查询depId|ctx=[fullName:{},depId:{}]", + fullName, + depId); } else { depId = departmentService.create(tmpName, parentId, sort); - // 创建同步记录 - ldapDepartmentService.create(depId, uuid, dn); + log.info( + "LDAP-部门同步处理-新建部门|ctx=[fullName:{},depId:{}]", fullName, depId); } + // 写入本地缓存 depIdKeyByName.put(fullName, depId); - // 写入本地缓存 - LdapDepartment storedLdapDepartment = new LdapDepartment(); - storedLdapDepartment.setUuid(uuid); - storedLdapDepartment.setDn(dn); - storedLdapDepartment.setDepartmentId(depId); - ldapDepartments.put(uuid, storedLdapDepartment); } } + if (i + 1 == length && tmpLdapDepartment == null) { + Integer tmpDepId = depIdKeyByName.get(fullName); + // 创建同步记录 + ldapDepartmentService.create(tmpDepId, uuid, dn); + + // 写入本地缓存 + LdapDepartment storedLdapDepartment = new LdapDepartment(); + storedLdapDepartment.setUuid(uuid); + storedLdapDepartment.setDn(dn); + storedLdapDepartment.setDepartmentId(tmpDepId); + ldapDepartments.put(uuid, storedLdapDepartment); + } + // 父级叠加 prevName = fullName; } @@ -155,23 +195,20 @@ public class LDAPBus { List uuidList = ouList.stream().map(LdapTransformDepartment::getUuid).toList(); List ldapDepartmentList = ldapDepartmentService.notChunkByUUIDList(uuidList); - for (LdapDepartment ldapDepartment : ldapDepartmentList) { - // 删除本地部门 - departmentService.destroy(ldapDepartment.getDepartmentId()); - // 删除关联记录 - ldapDepartmentService.destroy(ldapDepartment.getId()); + if (ldapDepartmentList != null && !ldapDepartmentList.isEmpty()) { + for (LdapDepartment ldapDepartment : ldapDepartmentList) { + // 删除本地部门 + departmentService.destroy(ldapDepartment.getDepartmentId()); + // 删除同步记录 + ldapDepartmentService.destroy(ldapDepartment.getId()); + } } } public void userSync() throws NamingException, IOException { LdapConfig ldapConfig = appConfigService.ldapConfig(); - List userList = - LdapUtil.users( - ldapConfig.getUrl(), - ldapConfig.getAdminUser(), - ldapConfig.getAdminPass(), - ldapConfig.getBaseDN()); + List userList = LdapUtil.users(ldapConfig, ldapConfig.getBaseDN()); if (userList == null || userList.isEmpty()) { return; @@ -181,6 +218,10 @@ public class LDAPBus { for (LdapTransformUser ldapTransformUser : userList) { if (ldapTransformUser.isBan()) { + log.info( + "LDAP-用户同步-用户被禁止|ctx=[dn:{},uuid={}]", + ldapTransformUser.getDn(), + ldapTransformUser.getId()); continue; } singleUserSync(ldapTransformUser, defaultAvatar); @@ -188,6 +229,11 @@ public class LDAPBus { } public User singleUserSync(LdapTransformUser ldapTransformUser, String defaultAvatar) { + log.info( + "*****START*****LDAP-用户同步-开始|ctx=[dn:{},uuid:{}]", + ldapTransformUser.getDn(), + ldapTransformUser.getId()); + // LDAP用户的名字 String ldapUserName = ldapTransformUser.getCn(); @@ -195,23 +241,24 @@ public class LDAPBus { Integer depId = departmentService.createWithChainList(ldapTransformUser.getOu()); Integer[] depIds = depId == 0 ? null : new Integer[] {depId}; - // LDAP用户在本地的缓存记录 - LdapUser ldapUser = ldapUserService.findByUUID(ldapTransformUser.getId()); User user; + // LDAP同步记录 + LdapUser ldapUser = ldapUserService.findByUUID(ldapTransformUser.getId()); + // 计算将LDAP用户关联到本地users表的email字段值 String localUserEmail = ldapTransformUser.getUid(); - if (StringUtil.isNotEmpty(ldapTransformUser.getEmail())) { - localUserEmail = ldapTransformUser.getEmail(); - } if (ldapUser == null) { // 检测localUserEmail是否存在 if (userService.find(localUserEmail) != null) { - localUserEmail = HelperUtil.randomString(5) + "_" + localUserEmail; + log.info("LDAP-用户同步-email重复|ctx=[email:{}]", localUserEmail); + return null; } - // LDAP用户数据缓存到本地 + + // 创建同步记录 ldapUser = ldapUserService.store(ldapTransformUser); + // 创建本地user user = userService.createWithDepIds( @@ -221,11 +268,26 @@ public class LDAPBus { HelperUtil.randomString(10), "", depIds); + // 将LDAP缓存数据与本地user关联 ldapUserService.updateUserId(ldapUser.getId(), user.getId()); + + log.info( + "LDAP-用户同步-录入数据|ctx=[userId:{},ldapUserId:{}]", user.getId(), ldapUser.getId()); } else { + log.info( + "LDAP-用户同步-检测变化值|ctx=[新dn:{},旧dn:{}]", + ldapTransformUser.getDn(), + ldapUser.getDn()); + user = userService.find(ldapUser.getUserId()); + if (user == null) { + // 同步记录创建了,但是user却没创建 + log.info( + "LDAP-用户同步-同步记录存在但user不存在|ctx=[dn:{},ldapUserId:{}]", + ldapTransformUser.getDn(), + ldapUser.getId()); user = userService.createWithDepIds( localUserEmail, @@ -235,6 +297,7 @@ public class LDAPBus { "", depIds); } + // 账号修改[账号有可能是email也有可能是uid] if (!localUserEmail.equals(user.getEmail())) { // 检测localUserEmail是否存在 @@ -243,19 +306,23 @@ public class LDAPBus { } userService.updateEmail(user.getId(), localUserEmail); } + // ldap-email的变化 if (!ldapUser.getEmail().equals(ldapTransformUser.getEmail())) { ldapUserService.updateEmail(ldapUser.getId(), ldapTransformUser.getEmail()); } + // ldap-uid的变化 if (!ldapUser.getUid().equals(ldapTransformUser.getUid())) { ldapUserService.updateUid(ldapUser.getId(), ldapTransformUser.getUid()); } + // 名字同步修改 if (!ldapUserName.equals(ldapUser.getCn())) { userService.updateName(user.getId(), ldapUserName); ldapUserService.updateCN(ldapUser.getId(), ldapUserName); } + // 部门修改同步 String newOU = String.join(",", ldapTransformUser.getOu()); if (!newOU.equals(ldapUser.getOu())) { diff --git a/playedu-api/playedu-common/src/main/java/xyz/playedu/common/service/LdapDepartmentService.java b/playedu-api/playedu-common/src/main/java/xyz/playedu/common/service/LdapDepartmentService.java index 3b72336..368a99f 100644 --- a/playedu-api/playedu-common/src/main/java/xyz/playedu/common/service/LdapDepartmentService.java +++ b/playedu-api/playedu-common/src/main/java/xyz/playedu/common/service/LdapDepartmentService.java @@ -30,4 +30,6 @@ public interface LdapDepartmentService extends IService { void destroy(Integer id); void create(Integer depId, String uuid, String dn); + + void updateDnById(Integer id, String dn); } diff --git a/playedu-api/playedu-common/src/main/java/xyz/playedu/common/service/impl/LdapDepartmentServiceImpl.java b/playedu-api/playedu-common/src/main/java/xyz/playedu/common/service/impl/LdapDepartmentServiceImpl.java index b177bf7..234c0fa 100644 --- a/playedu-api/playedu-common/src/main/java/xyz/playedu/common/service/impl/LdapDepartmentServiceImpl.java +++ b/playedu-api/playedu-common/src/main/java/xyz/playedu/common/service/impl/LdapDepartmentServiceImpl.java @@ -56,4 +56,12 @@ public class LdapDepartmentServiceImpl extends ServiceImpl users( - String url, String adminUser, String adminPass, String baseDN) + public static List users(LdapConfig ldapConfig, String filterScope) throws NamingException, IOException { - LdapContext ldapContext = initContext(url, adminUser, adminPass); + LdapContext ldapContext = + initContext( + ldapConfig.getUrl(), ldapConfig.getAdminUser(), ldapConfig.getAdminPass()); int pageSize = 1000; List users = new ArrayList<>(); @@ -111,11 +113,11 @@ public class LdapUtil { } NamingEnumeration result = - ldapContext.search(baseDN, USER_OBJECT_CLASS, controls); + ldapContext.search(filterScope, USER_OBJECT_CLASS, controls); while (result.hasMoreElements()) { SearchResult item = result.nextElement(); if (item != null) { - LdapTransformUser ldapTransformUser = parseTransformUser(item, baseDN); + LdapTransformUser ldapTransformUser = parseTransformUser(item, filterScope); if (ldapTransformUser != null) { users.add(ldapTransformUser); } @@ -153,9 +155,11 @@ public class LdapUtil { return null; } - public static List departments( - String url, String adminUser, String adminPass, String baseDN) throws NamingException { - LdapContext ldapContext = initContext(url, adminUser, adminPass); + public static List departments(LdapConfig ldapConfig, String baseDN) + throws NamingException { + LdapContext ldapContext = + initContext( + ldapConfig.getUrl(), ldapConfig.getAdminUser(), ldapConfig.getAdminPass()); SearchControls controls = new SearchControls(); controls.setSearchScope(SearchControls.SUBTREE_SCOPE); @@ -165,15 +169,16 @@ public class LdapUtil { String filter = "(objectClass=organizationalUnit)"; NamingEnumeration result = null; try { + log.info("LDAP-部门查询|条件[baseDN={},filter={}]", baseDN, filter); result = ldapContext.search(baseDN, filter, controls); } catch (NamingException e) { - log.error("LDAP部门查询失败", e); + log.error("LDAP-部门查询-失败|errMsg={}", e.getMessage()); } finally { closeContext(ldapContext); } if (result == null || !result.hasMoreElements()) { - log.info("LDAP部门为空"); + log.info("LDAP-部门查询-结果为空|条件[baseDN={},filter={}]", baseDN, filter); return null; } @@ -186,6 +191,7 @@ public class LdapUtil { if (item == null) { continue; } + Attributes attributes = item.getAttributes(); if (attributes == null) { continue; @@ -221,13 +227,7 @@ public class LdapUtil { } public static LdapTransformUser loginByMailOrUid( - String url, - String adminUser, - String adminPass, - String baseDN, - String mail, - String uid, - String password) + LdapConfig ldapConfig, String mail, String uid, String password) throws ServiceException, NamingException { if (StringUtil.isEmpty(mail) && StringUtil.isEmpty(uid)) { throw new ServiceException("mail和Uid不能同时为空"); @@ -249,10 +249,12 @@ public class LdapUtil { String filter = String.format("(&%s%s)", userFilter, USER_OBJECT_CLASS); - LdapContext ldapContext = initContext(url, adminUser, adminPass); + LdapContext ldapContext = + initContext( + ldapConfig.getUrl(), ldapConfig.getAdminUser(), ldapConfig.getAdminPass()); NamingEnumeration result = null; try { - result = ldapContext.search(baseDN, filter, controls); + result = ldapContext.search(ldapConfig.getBaseDN(), filter, controls); } catch (NamingException e) { log.error("LDAP-通过mail或uid登录失败", e); } finally { @@ -265,7 +267,8 @@ public class LdapUtil { } // 根据mail或uid查询出来的用户 - LdapTransformUser ldapUser = parseTransformUser(result.nextElement(), baseDN); + LdapTransformUser ldapUser = + parseTransformUser(result.nextElement(), ldapConfig.getBaseDN()); if (ldapUser == null) { log.info("LDAP-用户不存在"); return null; @@ -275,7 +278,11 @@ public class LdapUtil { // 登录成功则意味着密码正确 // 登录失败则意味着密码错误 try { - ldapContext = initContext(url, ldapUser.getDn() + "," + baseDN, password); + ldapContext = + initContext( + ldapConfig.getUrl(), + ldapUser.getDn() + "," + ldapConfig.getBaseDN(), + password); return ldapUser; } catch (Exception e) { // 无法登录->密码错误