feat(admin): 完善LDAP和用户管理功能

- 新增LDAPControllerService,实现LDAP配置管理与同步接口
- 新增LdapDepartmentVO,用于LDAP部门及用户结构封装
- 添加LdapScheduledTask,支持定时同步部门和用户信息
- 优化LdapService,调整获取用户的查询逻辑和DN转换方法
- 新增UserController,提供用户管理、LDAP信息查询及密码操作的REST接口
- 实现UserControllerService,完成用户及供应商的增删改查、授权和密码相关业务逻辑
- 支持供应商账号管理及批量导入功能
- 增加相关事务控制及数据校验,提升系统稳定性和安全性
This commit is contained in:
曹鹏飞 2026-04-08 17:14:35 +08:00
parent d4dcc3c5dd
commit 143d6b6146
6 changed files with 174 additions and 84 deletions

View File

@ -1,8 +1,11 @@
package com.nflg.wms.admin.controller;
import com.nflg.wms.admin.service.LDAPControllerService;
import com.nflg.wms.admin.service.UserControllerService;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.dto.LdapDepartmentDTO;
import com.nflg.wms.common.pojo.dto.LdapUserDTO;
import com.nflg.wms.common.pojo.dto.UserDTO;
import com.nflg.wms.common.pojo.qo.*;
import com.nflg.wms.common.pojo.vo.RoleSimpleVO;
@ -26,6 +29,9 @@ public class UserController extends BaseController {
@Resource
private UserControllerService userControllerService;
@Resource
private LDAPControllerService ldapControllerService;
/**
* 新增用户
*/
@ -108,14 +114,14 @@ public class UserController extends BaseController {
return ApiResult.success(userControllerService.search(request));
}
/**
* 从LDAP同步用户
*/
@PostMapping("syncFromLdap")
public ApiResult<Void> syncFromLdap() {
userControllerService.syncFromLdap();
return ApiResult.success();
}
// /**
// * 从LDAP同步用户
// */
// @PostMapping("syncFromLdap")
// public ApiResult<Void> syncFromLdap() {
// userControllerService.syncFromLdap();
// return ApiResult.success();
// }
/**
* 发送忘记密码邮件
@ -134,4 +140,23 @@ public class UserController extends BaseController {
public ApiResult<UserDTO> getUserInfo() {
return ApiResult.success(userControllerService.getUserInfo());
}
/**
* 获取LDAP部门
* @param ldapId LDAP表id
*/
@GetMapping("getLdapDepartments")
public ApiResult<LdapDepartmentDTO> getLdapDepartments(@RequestParam Long ldapId){
return ApiResult.success(ldapControllerService.searchAdSimple(ldapId));
}
/**
* 获取LDAP用户
* @param ldapId LDAP表id
* @param distinguishedName 部门的distinguishedName
*/
@GetMapping("getLdapUsers")
public ApiResult<List<LdapUserDTO>> getLdapUsers(@RequestParam Long ldapId, @RequestParam String distinguishedName){
return ApiResult.success(ldapControllerService.getUsers(ldapId,distinguishedName));
}
}

View File

@ -0,0 +1,24 @@
package com.nflg.wms.admin.pojo.vo;
import com.nflg.wms.common.pojo.dto.LdapUserDTO;
import lombok.Data;
import java.util.List;
@Data
public class LdapDepartmentVO {
/**
* 部门名称
*/
private String name;
private String distinguishedName;
/**
* 用户列表
*/
private List<LdapUserDTO> users;
private List<LdapDepartmentVO> children;
}

View File

@ -55,7 +55,7 @@ public class LdapScheduledTask {
ads.forEach(ad -> {
if (StrUtil.isBlank(ad.getNextSyncDate()) || StrUtil.equals(date, ad.getNextSyncDate())) {
departmentControllerService.syncFromLdap(ad);
userControllerService.syncFromLdap(ad);
// userControllerService.syncFromLdap(ad);
adSyncService.lambdaUpdate()
.eq(AdSync::getId, ad.getSyncId())
.set(AdSync::getNextSyncDate, LocalDate.now().plusDays(ad.getInterval()).format(DATE_FORMATTER))

View File

@ -1,9 +1,11 @@
package com.nflg.wms.admin.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.nflg.wms.common.pojo.dto.AdDTO;
import com.nflg.wms.common.pojo.dto.LdapDepartmentDTO;
import com.nflg.wms.common.pojo.dto.LdapUserDTO;
import com.nflg.wms.common.pojo.qo.EnableQO;
import com.nflg.wms.common.pojo.qo.LDAPAddQO;
import com.nflg.wms.common.pojo.qo.LDAPUpdateQO;
@ -12,8 +14,10 @@ import com.nflg.wms.common.pojo.vo.AdSyncVO;
import com.nflg.wms.common.util.UserUtil;
import com.nflg.wms.common.util.VUtil;
import com.nflg.wms.repository.entity.Ad;
import com.nflg.wms.repository.entity.User;
import com.nflg.wms.repository.service.IAdService;
import com.nflg.wms.repository.service.IAdSyncService;
import com.nflg.wms.repository.service.IUserService;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
@ -21,6 +25,7 @@ import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
@Component
@ -36,7 +41,7 @@ public class LDAPControllerService {
private DepartmentControllerService departmentControllerService;
@Resource
private UserControllerService userControllerService;
private IUserService userService;
public void add(@Valid LDAPAddQO request) {
Ad ad = Convert.convert(Ad.class, request);
@ -73,7 +78,7 @@ public class LDAPControllerService {
AdDTO ad = adService.getInfo(id);
VUtil.trueThrowBusinessError(Objects.isNull(ad)).throwMessage("数据不存在");
departmentControllerService.syncFromLdap(ad);
userControllerService.syncFromLdap(ad);
// userControllerService.syncFromLdap(ad);
}
public IPage<Ad> search(@Valid PageQO request) {
@ -93,4 +98,19 @@ public class LDAPControllerService {
ldapService.init(ad.getServer(), ad.getPort(), ad.getUserName(), ad.getUserPwd(), ad.getOu(), ad.getTimeout());
return ldapService.getDepartmentTree("",true);
}
public List<LdapUserDTO> getUsers(Long id,String distinguishedName){
AdDTO ad = adService.getInfo(id);
VUtil.trueThrowBusinessError(Objects.isNull(ad)).throwMessage("数据不存在");
LdapService ldapService = new LdapService();
ldapService.init(ad.getServer(), ad.getPort(), ad.getUserName(), ad.getUserPwd(), ad.getOu(), ad.getTimeout());
List<LdapUserDTO> users=ldapService.getUsers(distinguishedName);
if (CollectionUtil.isEmpty(users)){
return null;
}
List<User> dbUsers = userService.list();
return users.stream()
.filter(user -> dbUsers.stream().noneMatch(dbUser -> dbUser.getUserCode().equals(user.getUserCode())))
.toList();
}
}

View File

@ -128,6 +128,24 @@ public class LdapService {
}
}
/**
* 去除 DN 中的 baseDn 后缀得到相对路径
*/
private String toRelativeDn(String dn) {
if (StrUtil.isBlank(dn) || StrUtil.isBlank(baseDn)) {
return dn;
}
// 忽略大小写比较并去除末尾的 baseDn 部分
String dnLower = dn.toLowerCase();
String baseDnLower = baseDn.toLowerCase();
if (dnLower.endsWith("," + baseDnLower)) {
return dn.substring(0, dn.length() - baseDn.length() - 1);
} else if (dnLower.equals(baseDnLower)) {
return "";
}
return dn;
}
/**
* 获取所有用户
* @return 所有用户
@ -135,9 +153,10 @@ public class LdapService {
public List<LdapUserDTO> getUsers(String searchBaseDn) {
ldapTemplate.setIgnorePartialResultException(true);
log.info("开始获取用户信息");
String relativeDn = toRelativeDn(searchBaseDn);
LdapQuery query = LdapQueryBuilder.query()
.base(searchBaseDn)
.searchScope(SearchScope.SUBTREE)
.base(relativeDn)
.searchScope(SearchScope.ONELEVEL)
.where("objectClass").is("person");
List<LdapUserDTO> users = ldapTemplate.search(
query,

View File

@ -12,7 +12,9 @@ import com.nflg.wms.common.constant.Constant;
import com.nflg.wms.common.constant.STATE;
import com.nflg.wms.common.exception.NflgException;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.dto.*;
import com.nflg.wms.common.pojo.dto.SupplierExcelDTO;
import com.nflg.wms.common.pojo.dto.SupplierExcelExportDTO;
import com.nflg.wms.common.pojo.dto.UserDTO;
import com.nflg.wms.common.pojo.qo.*;
import com.nflg.wms.common.pojo.vo.RoleSimpleVO;
import com.nflg.wms.common.pojo.vo.UserSupplierItemVO;
@ -192,77 +194,77 @@ public class UserControllerService {
uService.enable(request.getId(), request.getEnable());
}
@Transactional
public void syncFromLdap() {
List<AdDTO> ads = adService.getList();
ads.parallelStream().forEach(this::syncFromLdap);
}
// @Transactional
// public void syncFromLdap() {
// List<AdDTO> ads = adService.getList();
// ads.parallelStream().forEach(this::syncFromLdap);
// }
@Transactional
public void syncFromLdap(AdDTO ad) {
LdapService ldapService = new LdapService();
ldapService.init(ad.getServer(), ad.getPort(), ad.getUserName(), ad.getUserPwd(), ad.getOu(), ad.getTimeout());
List<LdapUserDTO> users = ldapService.getUsers(ad.getMapFrom());
List<User> uforAdd = new ArrayList<>();
List<User> uforUpdate = new ArrayList<>();
List<UserInterior> uiforAdd = new ArrayList<>();
List<UserInterior> uiforUpdate = new ArrayList<>();
for (LdapUserDTO user : users) {
long deptId;
if (ad.getType() == 3) {
deptId = ad.getMapTo();
} else {
Department department = deptService.lambdaQuery().eq(Department::getSource, 1).eq(Department::getSourceId, user.getDepartmentDistinguishedName()).one();
if (Objects.isNull(department)) {
log.error("部门不存在:{}", user.getDepartmentDistinguishedName());
continue;
}
deptId = department.getId();
}
User u = uService.lambdaQuery().eq(User::getSource, 1).eq(User::getSourceId, user.getDistinguishedName()).one();
if (Objects.isNull(u)) {
u = new User()
.setId(IdUtil.getSnowflakeNextId())
.setUserName(user.getName())
.setUserCode(user.getUserCode())
.setSource(1)
.setSourceId(user.getDistinguishedName())
.setPassword("")
.setAdId(ad.getId())
.setMustResetPwd(false)
.setRemark("从LDAP同步")
.setCreateBy("自动同步")
.setCreateTime(LocalDateTime.now());
uforAdd.add(u);
uiforAdd.add(new UserInterior()
.setUserId(u.getId())
.setDeptId(deptId));
} else {
UserInterior ui = userInteriorService.lambdaQuery().eq(UserInterior::getUserId, u.getId()).one();
if (!Objects.equals(ui.getDeptId(), deptId))
ui.setDeptId(deptId);
uforUpdate.add(new User()
.setId(u.getId())
.setUserName(user.getName())
.setUserCode(user.getUserCode())
.setUpdateBy("自动同步")
.setUpdateTime(LocalDateTime.now()));
uiforUpdate.add(ui);
}
}
if (CollectionUtil.isNotEmpty(uforAdd)) {
uService.saveBatch(uforAdd);
}
if (CollectionUtil.isNotEmpty(uforUpdate)) {
uService.updateBatchById(uforUpdate);
}
if (CollectionUtil.isNotEmpty(uiforAdd)) {
userInteriorService.saveBatch(uiforAdd);
}
if (CollectionUtil.isNotEmpty(uiforUpdate)) {
userInteriorService.updateBatchById(uiforUpdate);
}
}
// @Transactional
// public void syncFromLdap(AdDTO ad) {
// LdapService ldapService = new LdapService();
// ldapService.init(ad.getServer(), ad.getPort(), ad.getUserName(), ad.getUserPwd(), ad.getOu(), ad.getTimeout());
// List<LdapUserDTO> users = ldapService.getUsers(ad.getMapFrom());
// List<User> uforAdd = new ArrayList<>();
// List<User> uforUpdate = new ArrayList<>();
// List<UserInterior> uiforAdd = new ArrayList<>();
// List<UserInterior> uiforUpdate = new ArrayList<>();
// for (LdapUserDTO user : users) {
// long deptId;
// if (ad.getType() == 3) {
// deptId = ad.getMapTo();
// } else {
// Department department = deptService.lambdaQuery().eq(Department::getSource, 1).eq(Department::getSourceId, user.getDepartmentDistinguishedName()).one();
// if (Objects.isNull(department)) {
// log.error("部门不存在:{}", user.getDepartmentDistinguishedName());
// continue;
// }
// deptId = department.getId();
// }
// User u = uService.lambdaQuery().eq(User::getSource, 1).eq(User::getSourceId, user.getDistinguishedName()).one();
// if (Objects.isNull(u)) {
// u = new User()
// .setId(IdUtil.getSnowflakeNextId())
// .setUserName(user.getName())
// .setUserCode(user.getUserCode())
// .setSource(1)
// .setSourceId(user.getDistinguishedName())
// .setPassword("")
// .setAdId(ad.getId())
// .setMustResetPwd(false)
// .setRemark("从LDAP同步")
// .setCreateBy("自动同步")
// .setCreateTime(LocalDateTime.now());
// uforAdd.add(u);
// uiforAdd.add(new UserInterior()
// .setUserId(u.getId())
// .setDeptId(deptId));
// } else {
// UserInterior ui = userInteriorService.lambdaQuery().eq(UserInterior::getUserId, u.getId()).one();
// if (!Objects.equals(ui.getDeptId(), deptId))
// ui.setDeptId(deptId);
// uforUpdate.add(new User()
// .setId(u.getId())
// .setUserName(user.getName())
// .setUserCode(user.getUserCode())
// .setUpdateBy("自动同步")
// .setUpdateTime(LocalDateTime.now()));
// uiforUpdate.add(ui);
// }
// }
// if (CollectionUtil.isNotEmpty(uforAdd)) {
// uService.saveBatch(uforAdd);
// }
// if (CollectionUtil.isNotEmpty(uforUpdate)) {
// uService.updateBatchById(uforUpdate);
// }
// if (CollectionUtil.isNotEmpty(uiforAdd)) {
// userInteriorService.saveBatch(uiforAdd);
// }
// if (CollectionUtil.isNotEmpty(uiforUpdate)) {
// userInteriorService.updateBatchById(uiforUpdate);
// }
// }
public void resetPassword(@Valid UserResetPasswordQO request) {
User user = uService.getById(request.getId());