mirror of
https://github.com/PlayEdu/PlayEdu
synced 2025-06-29 00:42:50 +08:00
优化Ldap的部门同步
This commit is contained in:
parent
8f27bb9fda
commit
8c905c6552
@ -30,20 +30,18 @@ import xyz.playedu.api.request.backend.DepartmentRequest;
|
||||
import xyz.playedu.api.request.backend.DepartmentSortRequest;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.bus.LDAPBus;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.context.BCtx;
|
||||
import xyz.playedu.common.domain.Department;
|
||||
import xyz.playedu.common.domain.User;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.service.AppConfigService;
|
||||
import xyz.playedu.common.service.DepartmentService;
|
||||
import xyz.playedu.common.service.UserService;
|
||||
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.UserPaginateFilter;
|
||||
import xyz.playedu.common.util.ldap.LdapUtil;
|
||||
import xyz.playedu.course.domain.Course;
|
||||
import xyz.playedu.course.domain.UserCourseRecord;
|
||||
import xyz.playedu.course.service.CourseDepartmentService;
|
||||
@ -70,7 +68,7 @@ public class DepartmentController {
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
@Autowired private AppConfigService appConfigService;
|
||||
@Autowired private LDAPBus ldapBus;
|
||||
|
||||
@GetMapping("/index")
|
||||
@Log(title = "部门-列表", businessType = BusinessTypeConstant.GET)
|
||||
@ -104,7 +102,7 @@ public class DepartmentController {
|
||||
@Log(title = "部门-新建", businessType = BusinessTypeConstant.INSERT)
|
||||
public JsonResponse store(@RequestBody @Validated DepartmentRequest req)
|
||||
throws NotFoundException {
|
||||
if (appConfigService.enabledLdapLogin()) {
|
||||
if (ldapBus.enabledLDAP()) {
|
||||
return JsonResponse.error("已启用LDAP服务,禁止添加部门");
|
||||
}
|
||||
departmentService.create(req.getName(), req.getParentId(), req.getSort());
|
||||
@ -124,7 +122,7 @@ public class DepartmentController {
|
||||
@Log(title = "部门-编辑", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse update(@PathVariable Integer id, @RequestBody DepartmentRequest req)
|
||||
throws NotFoundException {
|
||||
if (appConfigService.enabledLdapLogin()) {
|
||||
if (ldapBus.enabledLDAP()) {
|
||||
return JsonResponse.error("已启用LDAP服务,禁止添加部门");
|
||||
}
|
||||
Department department = departmentService.findOrFail(id);
|
||||
@ -136,7 +134,7 @@ public class DepartmentController {
|
||||
@GetMapping("/{id}/destroy")
|
||||
@Log(title = "部门-批量删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse preDestroy(@PathVariable Integer id) {
|
||||
if (appConfigService.enabledLdapLogin()) {
|
||||
if (ldapBus.enabledLDAP()) {
|
||||
return JsonResponse.error("已启用LDAP服务,禁止添加部门");
|
||||
}
|
||||
List<Integer> courseIds = courseDepartmentService.getCourseIdsByDepId(id);
|
||||
@ -180,7 +178,7 @@ public class DepartmentController {
|
||||
@DeleteMapping("/{id}")
|
||||
@Log(title = "部门-删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroy(@PathVariable Integer id) throws NotFoundException {
|
||||
if (appConfigService.enabledLdapLogin()) {
|
||||
if (ldapBus.enabledLDAP()) {
|
||||
return JsonResponse.error("已启用LDAP服务,禁止添加部门");
|
||||
}
|
||||
Department department = departmentService.findOrFail(id);
|
||||
@ -202,7 +200,7 @@ public class DepartmentController {
|
||||
@Log(title = "部门-更新父级", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse updateParent(@RequestBody @Validated DepartmentParentRequest req)
|
||||
throws NotFoundException {
|
||||
if (appConfigService.enabledLdapLogin()) {
|
||||
if (ldapBus.enabledLDAP()) {
|
||||
return JsonResponse.error("已启用LDAP服务,禁止添加部门");
|
||||
}
|
||||
departmentService.changeParent(req.getId(), req.getParentId(), req.getIds());
|
||||
@ -315,57 +313,7 @@ public class DepartmentController {
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
ldapBus.departmentSync();
|
||||
return JsonResponse.success();
|
||||
}
|
||||
}
|
||||
|
153
playedu-common/src/main/java/xyz/playedu/common/bus/LDAPBus.java
Normal file
153
playedu-common/src/main/java/xyz/playedu/common/bus/LDAPBus.java
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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.bus;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.common.domain.Department;
|
||||
import xyz.playedu.common.domain.LdapDepartment;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.service.AppConfigService;
|
||||
import xyz.playedu.common.service.DepartmentService;
|
||||
import xyz.playedu.common.service.LdapDepartmentService;
|
||||
import xyz.playedu.common.types.LdapConfig;
|
||||
import xyz.playedu.common.util.ldap.LdapTransformDepartment;
|
||||
import xyz.playedu.common.util.ldap.LdapUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class LDAPBus {
|
||||
|
||||
@Autowired private AppConfigService appConfigService;
|
||||
|
||||
@Autowired private DepartmentService departmentService;
|
||||
|
||||
@Autowired private LdapDepartmentService ldapDepartmentService;
|
||||
|
||||
public boolean enabledLDAP() {
|
||||
return appConfigService.enabledLdapLogin();
|
||||
}
|
||||
|
||||
public void departmentSync() throws NamingException, NotFoundException {
|
||||
LdapConfig ldapConfig = appConfigService.ldapConfig();
|
||||
|
||||
List<LdapTransformDepartment> ouList =
|
||||
LdapUtil.departments(
|
||||
ldapConfig.getUrl(),
|
||||
ldapConfig.getAdminUser(),
|
||||
ldapConfig.getAdminPass(),
|
||||
ldapConfig.getBaseDN());
|
||||
|
||||
if (ouList == null || ouList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 读取已经同步的记录
|
||||
Map<String, LdapDepartment> ldapDepartments =
|
||||
ldapDepartmentService.all().stream()
|
||||
.collect(Collectors.toMap(LdapDepartment::getUuid, e -> e));
|
||||
|
||||
// 本地缓存表
|
||||
HashMap<String, Integer> depIdKeyByName = new HashMap<>();
|
||||
// 全局排序计数
|
||||
Integer sort = 0;
|
||||
|
||||
// 新建+编辑的处理
|
||||
for (LdapTransformDepartment ldapTransformDepartment : ouList) {
|
||||
String uuid = ldapTransformDepartment.getUuid();
|
||||
String dn = ldapTransformDepartment.getDn();
|
||||
String[] tmpChains = dn.replace("ou=", "").split(",");
|
||||
String prevName = "";
|
||||
|
||||
// 同步记录
|
||||
LdapDepartment tmpLdapDepartment = ldapDepartments.get(uuid);
|
||||
if (tmpLdapDepartment != null && tmpLdapDepartment.getDn().equals(dn)) {
|
||||
// 当前部门已经同步 && 未发生改变
|
||||
continue;
|
||||
}
|
||||
|
||||
// 执行到这里的有两种情况:
|
||||
// 1.部门未同步
|
||||
// 2.部门已同步,但是发生了变化
|
||||
// 2.1 部门名称修改
|
||||
// 2.2 部门上级修改
|
||||
|
||||
int length = tmpChains.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
sort++;
|
||||
int parentId = 0;
|
||||
|
||||
String tmpName = tmpChains[i];
|
||||
|
||||
// 部门的链名=>父部门1,父部门2,子部门
|
||||
String fullName = tmpName;
|
||||
if (!prevName.isEmpty()) {
|
||||
fullName = prevName + "," + tmpName;
|
||||
// 取父级ID
|
||||
parentId = depIdKeyByName.get(prevName);
|
||||
}
|
||||
|
||||
// 最后一个记录 && 已存在部门-发生了变动
|
||||
if (i + 1 == length && tmpLdapDepartment != null) {
|
||||
Department tmpDepartment =
|
||||
departmentService.findOrFail(tmpLdapDepartment.getDepartmentId());
|
||||
departmentService.update(tmpDepartment, tmpName, parentId, sort);
|
||||
} else {
|
||||
// 检查本地是否有缓存
|
||||
Integer depId = depIdKeyByName.get(fullName);
|
||||
if (depId == null) {
|
||||
Department tmpDep = departmentService.findByName(tmpName, parentId);
|
||||
if (tmpDep != null) {
|
||||
depId = tmpDep.getId();
|
||||
} else {
|
||||
depId = departmentService.create(tmpName, parentId, sort);
|
||||
// 创建同步记录
|
||||
ldapDepartmentService.create(depId, uuid, dn);
|
||||
}
|
||||
// 写入本地缓存
|
||||
depIdKeyByName.put(fullName, depId);
|
||||
}
|
||||
}
|
||||
|
||||
// 父级叠加
|
||||
prevName = fullName;
|
||||
}
|
||||
}
|
||||
|
||||
// 删除的处理
|
||||
List<String> uuidList = ouList.stream().map(LdapTransformDepartment::getUuid).toList();
|
||||
List<LdapDepartment> ldapDepartmentList =
|
||||
ldapDepartmentService.notChunkByUUIDList(uuidList);
|
||||
for (LdapDepartment ldapDepartment : ldapDepartmentList) {
|
||||
// 删除本地部门
|
||||
departmentService.destroy(ldapDepartment.getDepartmentId());
|
||||
// 删除关联记录
|
||||
ldapDepartmentService.destroy(ldapDepartment.getId());
|
||||
}
|
||||
}
|
||||
|
||||
public void userSync() {}
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@TableName(value = "ldap_department")
|
||||
public class LdapDepartment implements Serializable {
|
||||
/** */
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
/** 唯一特征值 */
|
||||
private String uuid;
|
||||
|
||||
/** 部门ID */
|
||||
@JsonProperty("department_id")
|
||||
private Integer departmentId;
|
||||
|
||||
/** dn */
|
||||
private String dn;
|
||||
|
||||
/** */
|
||||
@JsonProperty("created_at")
|
||||
private Date createdAt;
|
||||
|
||||
/** */
|
||||
@JsonProperty("updated_at")
|
||||
private Date updatedAt;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** */
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/** */
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/** 唯一特征值 */
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/** 唯一特征值 */
|
||||
public void setUuid(String uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
/** 部门ID */
|
||||
public Integer getDepartmentId() {
|
||||
return departmentId;
|
||||
}
|
||||
|
||||
/** 部门ID */
|
||||
public void setDepartmentId(Integer departmentId) {
|
||||
this.departmentId = departmentId;
|
||||
}
|
||||
|
||||
/** dn */
|
||||
public String getDn() {
|
||||
return dn;
|
||||
}
|
||||
|
||||
/** dn */
|
||||
public void setDn(String dn) {
|
||||
this.dn = dn;
|
||||
}
|
||||
|
||||
/** */
|
||||
public Date getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
/** */
|
||||
public void setCreatedAt(Date createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
/** */
|
||||
public Date getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
/** */
|
||||
public void setUpdatedAt(Date updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (this == that) {
|
||||
return true;
|
||||
}
|
||||
if (that == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != that.getClass()) {
|
||||
return false;
|
||||
}
|
||||
LdapDepartment other = (LdapDepartment) that;
|
||||
return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
|
||||
&& (this.getUuid() == null
|
||||
? other.getUuid() == null
|
||||
: this.getUuid().equals(other.getUuid()))
|
||||
&& (this.getDepartmentId() == null
|
||||
? other.getDepartmentId() == null
|
||||
: this.getDepartmentId().equals(other.getDepartmentId()))
|
||||
&& (this.getDn() == null
|
||||
? other.getDn() == null
|
||||
: this.getDn().equals(other.getDn()))
|
||||
&& (this.getCreatedAt() == null
|
||||
? other.getCreatedAt() == null
|
||||
: this.getCreatedAt().equals(other.getCreatedAt()))
|
||||
&& (this.getUpdatedAt() == null
|
||||
? other.getUpdatedAt() == null
|
||||
: this.getUpdatedAt().equals(other.getUpdatedAt()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
|
||||
result = prime * result + ((getUuid() == null) ? 0 : getUuid().hashCode());
|
||||
result = prime * result + ((getDepartmentId() == null) ? 0 : getDepartmentId().hashCode());
|
||||
result = prime * result + ((getDn() == null) ? 0 : getDn().hashCode());
|
||||
result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode());
|
||||
result = prime * result + ((getUpdatedAt() == null) ? 0 : getUpdatedAt().hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getClass().getSimpleName());
|
||||
sb.append(" [");
|
||||
sb.append("Hash = ").append(hashCode());
|
||||
sb.append(", id=").append(id);
|
||||
sb.append(", uuid=").append(uuid);
|
||||
sb.append(", departmentId=").append(departmentId);
|
||||
sb.append(", dn=").append(dn);
|
||||
sb.append(", createdAt=").append(createdAt);
|
||||
sb.append(", updatedAt=").append(updatedAt);
|
||||
sb.append(", serialVersionUID=").append(serialVersionUID);
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -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.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
import xyz.playedu.common.domain.LdapDepartment;
|
||||
|
||||
/**
|
||||
* @author tengyongzhi
|
||||
* @description 针对表【ldap_department】的数据库操作Mapper
|
||||
* @createDate 2023-11-13 15:46:06 @Entity xyz.playedu.common.domain.LdapDepartment
|
||||
*/
|
||||
public interface LdapDepartmentMapper extends BaseMapper<LdapDepartment> {}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import xyz.playedu.common.domain.LdapDepartment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface LdapDepartmentService extends IService<LdapDepartment> {
|
||||
|
||||
List<LdapDepartment> all();
|
||||
|
||||
List<LdapDepartment> notChunkByUUIDList(List<String> uuidList);
|
||||
|
||||
void destroy(Integer id);
|
||||
|
||||
void create(Integer depId, String uuid, String dn);
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import xyz.playedu.common.domain.LdapDepartment;
|
||||
import xyz.playedu.common.mapper.LdapDepartmentMapper;
|
||||
import xyz.playedu.common.service.LdapDepartmentService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class LdapDepartmentServiceImpl extends ServiceImpl<LdapDepartmentMapper, LdapDepartment>
|
||||
implements LdapDepartmentService {
|
||||
|
||||
@Override
|
||||
public List<LdapDepartment> all() {
|
||||
return list();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LdapDepartment> notChunkByUUIDList(List<String> uuidList) {
|
||||
return list(query().getWrapper().notIn("uuid", uuidList));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy(Integer id) {
|
||||
remove(query().getWrapper().eq("id", id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create(Integer depId, String uuid, String dn) {
|
||||
LdapDepartment ldapDepartment = new LdapDepartment();
|
||||
ldapDepartment.setDepartmentId(depId);
|
||||
ldapDepartment.setDn(dn);
|
||||
ldapDepartment.setUuid(uuid);
|
||||
ldapDepartment.setCreatedAt(new Date());
|
||||
ldapDepartment.setUpdatedAt(new Date());
|
||||
|
||||
save(ldapDepartment);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.util.ldap;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LdapTransformDepartment {
|
||||
private String uuid;
|
||||
private String dn;
|
||||
}
|
@ -61,7 +61,7 @@ public class LdapUtil {
|
||||
// 公用属性
|
||||
"mail",
|
||||
};
|
||||
private static final String[] OU_RETURN_ATTRS = new String[] {"ou"};
|
||||
private static final String[] OU_RETURN_ATTRS = new String[] {"ou", "usncreated"};
|
||||
|
||||
public static LdapContext initContext(String url, String adminUser, String adminPass)
|
||||
throws NamingException {
|
||||
@ -110,7 +110,7 @@ public class LdapUtil {
|
||||
return users;
|
||||
}
|
||||
|
||||
public static List<String> departments(
|
||||
public static List<LdapTransformDepartment> departments(
|
||||
String url, String adminUser, String adminPass, String baseDN) throws NamingException {
|
||||
LdapContext ldapContext = initContext(url, adminUser, adminPass);
|
||||
|
||||
@ -137,12 +137,24 @@ public class LdapUtil {
|
||||
// baseDN中的ou作用域
|
||||
String ouScopesStr = baseDNOuScope(baseDN);
|
||||
|
||||
List<String> units = new ArrayList<>();
|
||||
List<LdapTransformDepartment> units = new ArrayList<>();
|
||||
while (result.hasMoreElements()) {
|
||||
SearchResult item = result.nextElement();
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
Attributes attributes = item.getAttributes();
|
||||
if (attributes == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 唯一特征值
|
||||
String uSNCreated = (String) attributes.get("uSNCreated").get();
|
||||
if (StringUtil.isEmpty(uSNCreated)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 组织DN
|
||||
String name = item.getName();
|
||||
if (name.isEmpty()) {
|
||||
name = ouScopesStr;
|
||||
@ -150,20 +162,19 @@ public class LdapUtil {
|
||||
name = name + (ouScopesStr.isEmpty() ? "" : "," + ouScopesStr);
|
||||
}
|
||||
|
||||
units.add(name);
|
||||
// 将DN反转
|
||||
List<String> tmp = new ArrayList<>(List.of(name.split(",")));
|
||||
Collections.reverse(tmp);
|
||||
name = String.join(",", tmp);
|
||||
|
||||
LdapTransformDepartment ldapDepartment = new LdapTransformDepartment();
|
||||
ldapDepartment.setUuid(uSNCreated);
|
||||
ldapDepartment.setDn(name.toLowerCase());
|
||||
|
||||
units.add(ldapDepartment);
|
||||
}
|
||||
|
||||
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;
|
||||
return units;
|
||||
}
|
||||
|
||||
public static LdapTransformUser loginByMailOrUid(
|
||||
@ -200,13 +211,13 @@ public class LdapUtil {
|
||||
try {
|
||||
result = ldapContext.search(baseDN, filter, controls);
|
||||
} catch (NamingException e) {
|
||||
log.error("通过mail或uid登录失败", e);
|
||||
log.error("LDAP-通过mail或uid登录失败", e);
|
||||
} finally {
|
||||
closeContext(ldapContext);
|
||||
}
|
||||
|
||||
if (result == null || !result.hasMoreElements()) {
|
||||
log.info("用户不存在");
|
||||
log.info("LDAP-用户不存在");
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -251,23 +262,19 @@ public class LdapUtil {
|
||||
Collections.reverse(ou);
|
||||
ldapUser.setOu(ou);
|
||||
|
||||
log.info("ldapUser={}", ldapUser);
|
||||
|
||||
// 使用用户dn+提交的密码去登录ldap系统
|
||||
// 登录成功则意味着密码正确
|
||||
// 登录失败则意味着密码错误
|
||||
try {
|
||||
ldapContext = initContext(url, ldapUser.getDn() + "," + baseDN, password);
|
||||
log.info("LDAP登录成功");
|
||||
return ldapUser;
|
||||
} catch (Exception e) {
|
||||
// 无法登录->密码错误
|
||||
log.info("LDAP用户提交的密码错误");
|
||||
log.error("LDAP-登录失败", e);
|
||||
return null;
|
||||
} finally {
|
||||
ldapContext.close();
|
||||
}
|
||||
|
||||
return ldapUser;
|
||||
}
|
||||
|
||||
private static String baseDNOuScope(String baseDN) {
|
||||
@ -288,7 +295,7 @@ public class LdapUtil {
|
||||
try {
|
||||
ldapCtx.close();
|
||||
} catch (NamingException e) {
|
||||
log.error("Failed to close ldap context", e);
|
||||
log.error("LDAP-资源释放失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="xyz.playedu.common.mapper.LdapDepartmentMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="xyz.playedu.common.domain.LdapDepartment">
|
||||
<id property="id" column="id" jdbcType="INTEGER"/>
|
||||
<result property="uuid" column="uuid" jdbcType="VARCHAR"/>
|
||||
<result property="departmentId" column="department_id" jdbcType="INTEGER"/>
|
||||
<result property="dn" column="dn" jdbcType="VARCHAR"/>
|
||||
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
|
||||
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,uuid,department_id,
|
||||
dn,created_at,updated_at
|
||||
</sql>
|
||||
</mapper>
|
@ -713,6 +713,27 @@ public class MigrationCheck implements CommandLineRunner {
|
||||
""");
|
||||
}
|
||||
});
|
||||
add(
|
||||
new HashMap<>() {
|
||||
{
|
||||
put("table", "ldap_department");
|
||||
put("name", "20231113_15_44_17_ldap_department");
|
||||
put(
|
||||
"sql",
|
||||
"""
|
||||
CREATE TABLE `ldap_department` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||
`uuid` varchar(64) NOT NULL DEFAULT '' COMMENT '唯一特征值',
|
||||
`department_id` int(11) NOT NULL DEFAULT 0 COMMENT '部门ID',
|
||||
`dn` varchar(120) NOT NULL DEFAULT '' COMMENT 'dn',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `unique_uuid` (`uuid`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
""");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user