mirror of
https://github.com/PlayEdu/PlayEdu
synced 2025-06-22 11:52:43 +08:00
新增LDAP的部门同步
This commit is contained in:
parent
a82e2992b4
commit
b685a21717
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package xyz.playedu.api.controller.backend;
|
package xyz.playedu.api.controller.backend;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import org.apache.commons.collections4.MapUtils;
|
import org.apache.commons.collections4.MapUtils;
|
||||||
@ -39,8 +40,10 @@ import xyz.playedu.common.service.AppConfigService;
|
|||||||
import xyz.playedu.common.service.DepartmentService;
|
import xyz.playedu.common.service.DepartmentService;
|
||||||
import xyz.playedu.common.service.UserService;
|
import xyz.playedu.common.service.UserService;
|
||||||
import xyz.playedu.common.types.JsonResponse;
|
import xyz.playedu.common.types.JsonResponse;
|
||||||
|
import xyz.playedu.common.types.LdapConfig;
|
||||||
import xyz.playedu.common.types.paginate.PaginationResult;
|
import xyz.playedu.common.types.paginate.PaginationResult;
|
||||||
import xyz.playedu.common.types.paginate.UserPaginateFilter;
|
import xyz.playedu.common.types.paginate.UserPaginateFilter;
|
||||||
|
import xyz.playedu.common.util.ldap.LdapUtil;
|
||||||
import xyz.playedu.course.domain.Course;
|
import xyz.playedu.course.domain.Course;
|
||||||
import xyz.playedu.course.domain.UserCourseRecord;
|
import xyz.playedu.course.domain.UserCourseRecord;
|
||||||
import xyz.playedu.course.service.CourseDepartmentService;
|
import xyz.playedu.course.service.CourseDepartmentService;
|
||||||
@ -144,7 +147,7 @@ public class DepartmentController {
|
|||||||
data.put("users", new ArrayList<>());
|
data.put("users", new ArrayList<>());
|
||||||
data.put("children", departmentService.listByParentId(id));
|
data.put("children", departmentService.listByParentId(id));
|
||||||
|
|
||||||
if (courseIds != null && courseIds.size() > 0) {
|
if (courseIds != null && !courseIds.isEmpty()) {
|
||||||
data.put(
|
data.put(
|
||||||
"courses",
|
"courses",
|
||||||
courseService.chunks(
|
courseService.chunks(
|
||||||
@ -156,7 +159,7 @@ public class DepartmentController {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if (userIds != null && userIds.size() > 0) {
|
if (userIds != null && !userIds.isEmpty()) {
|
||||||
data.put(
|
data.put(
|
||||||
"users",
|
"users",
|
||||||
userService.chunks(
|
userService.chunks(
|
||||||
@ -244,7 +247,7 @@ public class DepartmentController {
|
|||||||
PaginationResult<User> users = userService.paginate(page, size, filter);
|
PaginationResult<User> users = userService.paginate(page, size, filter);
|
||||||
|
|
||||||
List<Course> courses;
|
List<Course> courses;
|
||||||
if (courseIdsStr != null && courseIdsStr.trim().length() > 0) {
|
if (courseIdsStr != null && !courseIdsStr.trim().isEmpty()) {
|
||||||
// 指定了需要显示的线上课
|
// 指定了需要显示的线上课
|
||||||
courses =
|
courses =
|
||||||
courseService.chunks(
|
courseService.chunks(
|
||||||
@ -306,4 +309,63 @@ public class DepartmentController {
|
|||||||
|
|
||||||
return JsonResponse.data(data);
|
return JsonResponse.data(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||||
|
@PostMapping("/ldap-sync")
|
||||||
|
@Log(title = "部门-LDAP同步", businessType = BusinessTypeConstant.INSERT)
|
||||||
|
@SneakyThrows
|
||||||
|
public JsonResponse ldapSync() {
|
||||||
|
LdapConfig ldapConfig = appConfigService.ldapConfig();
|
||||||
|
|
||||||
|
List<String> ouList =
|
||||||
|
LdapUtil.departments(
|
||||||
|
ldapConfig.getUrl(),
|
||||||
|
ldapConfig.getAdminUser(),
|
||||||
|
ldapConfig.getAdminPass(),
|
||||||
|
ldapConfig.getBaseDN());
|
||||||
|
|
||||||
|
if (ouList == null || ouList.isEmpty()) {
|
||||||
|
return JsonResponse.error("部门为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap<String, Integer> depIdKeyByName = new HashMap<>();
|
||||||
|
Integer sort = 0;
|
||||||
|
|
||||||
|
for (String department : ouList) {
|
||||||
|
String[] tmp = department.toLowerCase().split(",");
|
||||||
|
String prevName = "";
|
||||||
|
for (String s : tmp) {
|
||||||
|
// 控制部门排序
|
||||||
|
sort++;
|
||||||
|
// 当前的子部门名
|
||||||
|
String tmpName = s.replace("ou=", "");
|
||||||
|
// 父部门id
|
||||||
|
Integer parentId = 0;
|
||||||
|
// 部门的链名=>父部门1,父部门2,子部门
|
||||||
|
String fullName = tmpName;
|
||||||
|
if (!prevName.isEmpty()) {
|
||||||
|
fullName = prevName + "," + tmpName;
|
||||||
|
parentId = depIdKeyByName.get(prevName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否已经创建
|
||||||
|
Integer depId = depIdKeyByName.get(tmpName);
|
||||||
|
if (depId == null) {
|
||||||
|
// 检查是否已经创建
|
||||||
|
Department tmpDep = departmentService.findByName(tmpName, parentId);
|
||||||
|
if (tmpDep == null) {
|
||||||
|
// 创建部门
|
||||||
|
Integer tmpDepId = departmentService.create(tmpName, parentId, sort);
|
||||||
|
depIdKeyByName.put(fullName, tmpDepId);
|
||||||
|
} else {
|
||||||
|
depIdKeyByName.put(fullName, tmpDep.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prevName = fullName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsonResponse.success();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,5 +41,4 @@ public class ConfigConstant {
|
|||||||
public static final String LDAP_ADMIN_USER = "ldap.admin_user";
|
public static final String LDAP_ADMIN_USER = "ldap.admin_user";
|
||||||
public static final String LDAP_ADMIN_PASS = "ldap.admin_pass";
|
public static final String LDAP_ADMIN_PASS = "ldap.admin_pass";
|
||||||
public static final String LDAP_BASE_DN = "ldap.base_dn";
|
public static final String LDAP_BASE_DN = "ldap.base_dn";
|
||||||
public static final String LDAP_USER_DN_PREFIX = "ldap.user_dn_prefix";
|
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package xyz.playedu.common.service;
|
|||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
import xyz.playedu.common.domain.AppConfig;
|
import xyz.playedu.common.domain.AppConfig;
|
||||||
|
import xyz.playedu.common.types.LdapConfig;
|
||||||
import xyz.playedu.common.types.config.MinioConfig;
|
import xyz.playedu.common.types.config.MinioConfig;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -39,4 +40,6 @@ public interface AppConfigService extends IService<AppConfig> {
|
|||||||
boolean enabledLdapLogin();
|
boolean enabledLdapLogin();
|
||||||
|
|
||||||
String defaultAvatar();
|
String defaultAvatar();
|
||||||
|
|
||||||
|
LdapConfig ldapConfig();
|
||||||
}
|
}
|
||||||
|
@ -66,4 +66,6 @@ public interface DepartmentService extends IService<Department> {
|
|||||||
List<Department> chunk(List<Integer> ids);
|
List<Department> chunk(List<Integer> ids);
|
||||||
|
|
||||||
Integer createWithChainList(List<String> ou);
|
Integer createWithChainList(List<String> ou);
|
||||||
|
|
||||||
|
Department findByName(String name, Integer parentId);
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,10 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import xyz.playedu.common.constant.ConfigConstant;
|
import xyz.playedu.common.constant.ConfigConstant;
|
||||||
import xyz.playedu.common.domain.AppConfig;
|
import xyz.playedu.common.domain.AppConfig;
|
||||||
|
import xyz.playedu.common.exception.ServiceException;
|
||||||
import xyz.playedu.common.mapper.AppConfigMapper;
|
import xyz.playedu.common.mapper.AppConfigMapper;
|
||||||
import xyz.playedu.common.service.AppConfigService;
|
import xyz.playedu.common.service.AppConfigService;
|
||||||
|
import xyz.playedu.common.types.LdapConfig;
|
||||||
import xyz.playedu.common.types.config.MinioConfig;
|
import xyz.playedu.common.types.config.MinioConfig;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -117,4 +119,29 @@ public class AppConfigServiceImpl extends ServiceImpl<AppConfigMapper, AppConfig
|
|||||||
getOne(query().getWrapper().eq("key_name", ConfigConstant.MEMBER_DEFAULT_AVATAR));
|
getOne(query().getWrapper().eq("key_name", ConfigConstant.MEMBER_DEFAULT_AVATAR));
|
||||||
return appConfig.getKeyValue();
|
return appConfig.getKeyValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LdapConfig ldapConfig() {
|
||||||
|
Map<String, String> config = keyValues();
|
||||||
|
|
||||||
|
LdapConfig ldapConfig = new LdapConfig();
|
||||||
|
ldapConfig.setEnabled(config.get(ConfigConstant.LDAP_ENABLED).equals("1"));
|
||||||
|
ldapConfig.setUrl(config.get(ConfigConstant.LDAP_URL));
|
||||||
|
ldapConfig.setAdminUser(config.get(ConfigConstant.LDAP_ADMIN_USER));
|
||||||
|
ldapConfig.setAdminPass(config.get(ConfigConstant.LDAP_ADMIN_PASS));
|
||||||
|
ldapConfig.setBaseDN(config.get(ConfigConstant.LDAP_BASE_DN));
|
||||||
|
|
||||||
|
if (!ldapConfig.getEnabled()) {
|
||||||
|
throw new ServiceException("LDAP服务未启用");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ldapConfig.getUrl().isEmpty()
|
||||||
|
|| ldapConfig.getAdminUser().isEmpty()
|
||||||
|
|| ldapConfig.getAdminPass().isEmpty()
|
||||||
|
|| ldapConfig.getBaseDN().isEmpty()) {
|
||||||
|
throw new ServiceException("LDAP服务未配置");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ldapConfig;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,4 +288,9 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
|
|||||||
}
|
}
|
||||||
return department.getId();
|
return department.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Department findByName(String name, Integer parentId) {
|
||||||
|
return getOne(query().getWrapper().eq("name", name).eq("parent_id", parentId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 杭州白书科技有限公司
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package xyz.playedu.common.types;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class LdapConfig {
|
||||||
|
private Boolean enabled;
|
||||||
|
private String url;
|
||||||
|
private String adminUser;
|
||||||
|
private String adminPass;
|
||||||
|
private String baseDN;
|
||||||
|
}
|
@ -110,8 +110,10 @@ public class LdapUtil {
|
|||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> departments(LdapContext ldapContext, String baseDN)
|
public static List<String> departments(
|
||||||
throws NamingException {
|
String url, String adminUser, String adminPass, String baseDN) throws NamingException {
|
||||||
|
LdapContext ldapContext = initContext(url, adminUser, adminPass);
|
||||||
|
|
||||||
SearchControls controls = new SearchControls();
|
SearchControls controls = new SearchControls();
|
||||||
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||||
controls.setReturningAttributes(OU_RETURN_ATTRS);
|
controls.setReturningAttributes(OU_RETURN_ATTRS);
|
||||||
@ -132,16 +134,42 @@ public class LdapUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> ouScopes = new ArrayList<>();
|
||||||
|
String[] rdnList = baseDN.toLowerCase().split(",");
|
||||||
|
for (int i = 0; i < rdnList.length; i++) {
|
||||||
|
if (rdnList[i].startsWith("ou=")) {
|
||||||
|
ouScopes.add(rdnList[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String ouScopesStr = String.join(",", ouScopes);
|
||||||
|
|
||||||
List<String> units = new ArrayList<>();
|
List<String> units = new ArrayList<>();
|
||||||
while (result.hasMoreElements()) {
|
while (result.hasMoreElements()) {
|
||||||
SearchResult item = result.nextElement();
|
SearchResult item = result.nextElement();
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
units.add(item.getName());
|
String name = item.getName();
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
name = ouScopesStr;
|
||||||
|
} else {
|
||||||
|
name = name + (ouScopesStr.isEmpty() ? "" : "," + ouScopesStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
units.add(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return units;
|
List<String> reverseUnits = new ArrayList<>();
|
||||||
|
if (!units.isEmpty()) {
|
||||||
|
units.forEach(
|
||||||
|
item -> {
|
||||||
|
List<String> tmp = new ArrayList<>(List.of(item.split(",")));
|
||||||
|
Collections.reverse(tmp);
|
||||||
|
reverseUnits.add(String.join(",", tmp));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return reverseUnits;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LdapTransformUser loginByMailOrUid(
|
public static LdapTransformUser loginByMailOrUid(
|
||||||
|
@ -276,16 +276,6 @@ public class AppConfigCheck implements CommandLineRunner {
|
|||||||
setHelp("从LDAP根节点搜索用户");
|
setHelp("从LDAP根节点搜索用户");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new AppConfig() {
|
|
||||||
{
|
|
||||||
setName("附件用户DN");
|
|
||||||
setSort(70);
|
|
||||||
setFieldType(BackendConstant.APP_CONFIG_FIELD_TYPE_TEXT);
|
|
||||||
setKeyName(ConfigConstant.LDAP_USER_DN_PREFIX);
|
|
||||||
setKeyValue("");
|
|
||||||
setHelp("搜索用户时,基于基础DN的搜索范围限制");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -37,6 +37,21 @@ public class UpgradeCheck implements CommandLineRunner {
|
|||||||
@Override
|
@Override
|
||||||
public void run(String... args) throws Exception {
|
public void run(String... args) throws Exception {
|
||||||
upgrade_v1_beta7();
|
upgrade_v1_beta7();
|
||||||
|
upgrade_v1_4();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void upgrade_v1_4() {
|
||||||
|
appConfigService.remove(
|
||||||
|
appConfigService
|
||||||
|
.query()
|
||||||
|
.getWrapper()
|
||||||
|
.in(
|
||||||
|
"key_name",
|
||||||
|
new ArrayList<>() {
|
||||||
|
{
|
||||||
|
add("ldap.user_dn_prefix");
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void upgrade_v1_beta7() {
|
private void upgrade_v1_beta7() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user