Merge remote-tracking branch 'base-version/main' into dev

This commit is contained in:
chenbowen
2025-10-31 09:29:56 +08:00
43 changed files with 2454 additions and 65 deletions

View File

@@ -31,6 +31,11 @@
<artifactId>zt-spring-boot-starter-biz-data-permission</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.zt.plat</groupId>
<artifactId>zt-spring-boot-starter-biz-tenant</artifactId>
<version>${revision}</version>
</dependency>
<!-- Test 测试相关 -->
<dependency>
<groupId>com.zt.plat</groupId>

View File

@@ -4,11 +4,15 @@ import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zt.plat.framework.common.pojo.CompanyDeptInfo;
import com.zt.plat.framework.security.core.LoginUser;
import com.zt.plat.framework.tenant.core.context.CompanyContextHolder;
import com.zt.plat.framework.web.core.util.WebFrameworkUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@@ -22,43 +26,85 @@ import static com.zt.plat.framework.security.core.util.SecurityFrameworkUtils.ge
public class BusinessDeptHandleUtil {
public static Set<CompanyDeptInfo> getBelongCompanyAndDept(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.setContentType("application/json;charset=UTF-8");
String companyId = request.getHeader("visit-company-id");
String deptId = request.getHeader("visit-dept-id");
LoginUser loginUser = Optional.ofNullable(getLoginUser()).orElse(new LoginUser().setInfo(new HashMap<>()));
Set<CompanyDeptInfo> companyDeptSet = JSONUtil.parseArray(loginUser.getInfo().getOrDefault(LoginUser.INFO_KEY_COMPANY_DEPT_SET, "[]")).stream()
String companyIdHeader = request.getHeader(WebFrameworkUtils.HEADER_VISIT_COMPANY_ID);
String deptIdHeader = request.getHeader(WebFrameworkUtils.HEADER_VISIT_DEPT_ID);
LoginUser currentLoginUser = getLoginUser();
Map<String, String> extraInfo = Optional.ofNullable(currentLoginUser)
.map(LoginUser::getInfo)
.orElseGet(HashMap::new);
if (currentLoginUser != null && currentLoginUser.getInfo() == null) {
currentLoginUser.setInfo(extraInfo);
}
Set<CompanyDeptInfo> companyDeptSet = JSONUtil.parseArray(extraInfo.getOrDefault(LoginUser.INFO_KEY_COMPANY_DEPT_SET, "[]")).stream()
.map(obj -> JSONUtil.toBean((JSONObject) obj, CompanyDeptInfo.class))
.collect(Collectors.toSet());
// 1. 有 companyId
if (companyId != null && !companyId.isBlank()) {
if (companyIdHeader != null && !companyIdHeader.isBlank()) {
// 根据请求头中的公司 ID 过滤出当前用户的公司部门信息
Set<CompanyDeptInfo> companyDeptSetByCompanyId = companyDeptSet.stream().filter(companyDeptInfo -> companyDeptInfo.getCompanyId().toString().equals(companyId)).collect(Collectors.toSet());
Set<CompanyDeptInfo> companyDeptSetByCompanyId = companyDeptSet.stream()
.filter(companyDeptInfo -> companyDeptInfo.getCompanyId().toString().equals(companyIdHeader))
.collect(Collectors.toSet());
if (companyDeptSetByCompanyId.isEmpty()) {
// 当前公司下没有部门
CompanyDeptInfo data = new CompanyDeptInfo();
data.setCompanyId(Long.valueOf(companyId));
data.setCompanyId(Long.valueOf(companyIdHeader));
data.setDeptId(0L);
return new HashSet<>(singleton(data));
}
// 如果有 deptId校验其是否属于该 companyId
if (deptId != null) {
boolean valid = companyDeptSetByCompanyId.stream().anyMatch(info -> String.valueOf(info.getDeptId()).equals(deptId));
if (deptIdHeader != null) {
boolean valid = companyDeptSetByCompanyId.stream().anyMatch(info -> String.valueOf(info.getDeptId()).equals(deptIdHeader));
if (!valid) {
return null;
}else{
} else {
// 部门存在,放行
return new HashSet<>();
}
}
if (companyDeptSetByCompanyId.size() == 1) {
CompanyDeptInfo singleCompanyDept = companyDeptSetByCompanyId.iterator().next();
if (applyAutoSelection(currentLoginUser, request, singleCompanyDept)) {
return Collections.emptySet();
}
}
return companyDeptSetByCompanyId;
}
// 2. 没有公司信息,尝试唯一性自动推断
// 如果当前用户下只有一个公司和部门的对于关系
if (companyDeptSet.size() == 1) {
CompanyDeptInfo companyDeptInfo = companyDeptSet.iterator().next();
if (applyAutoSelection(currentLoginUser, request, companyDeptInfo)) {
return Collections.emptySet();
}
return new HashSet<>(singleton(companyDeptInfo));
} else {
return companyDeptSet;
}
return companyDeptSet;
}
private static boolean applyAutoSelection(LoginUser loginUser, HttpServletRequest request, CompanyDeptInfo info) {
if (info == null || info.getCompanyId() == null || info.getCompanyId() <= 0
|| info.getDeptId() == null || info.getDeptId() <= 0) {
return false;
}
if (loginUser != null) {
loginUser.setVisitCompanyId(info.getCompanyId());
loginUser.setVisitCompanyName(info.getCompanyName());
loginUser.setVisitDeptId(info.getDeptId());
loginUser.setVisitDeptName(info.getDeptName());
}
request.setAttribute(WebFrameworkUtils.HEADER_VISIT_COMPANY_ID, info.getCompanyId());
if (info.getCompanyName() != null) {
request.setAttribute(WebFrameworkUtils.HEADER_VISIT_COMPANY_NAME, info.getCompanyName());
}
request.setAttribute(WebFrameworkUtils.HEADER_VISIT_DEPT_ID, info.getDeptId());
if (info.getDeptName() != null) {
request.setAttribute(WebFrameworkUtils.HEADER_VISIT_DEPT_NAME, info.getDeptName());
}
CompanyContextHolder.setIgnore(false);
CompanyContextHolder.setCompanyId(info.getCompanyId());
return true;
}
}

View File

@@ -20,30 +20,68 @@ public class CompanyVisitContextInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 解析 header 并设置 visitCompanyId
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
Long companyId = WebFrameworkUtils.getCompanyId(request);
// 优先使用请求头上的公司信息,若缺失则回退到请求属性或当前登录用户已缓存的访问公司
if (companyId == null || companyId <= 0L) {
Long attrCompanyId = resolveLong(request.getAttribute(WebFrameworkUtils.HEADER_VISIT_COMPANY_ID));
if (attrCompanyId != null && attrCompanyId > 0L) {
companyId = attrCompanyId;
} else if (loginUser != null && loginUser.getVisitCompanyId() != null && loginUser.getVisitCompanyId() > 0L) {
companyId = loginUser.getVisitCompanyId();
}
}
String companyName = WebFrameworkUtils.getCompanyName(request);
if (companyId <= 0L) {
// 如果没有设置 companyId则忽略
if (companyName == null || companyName.isEmpty()) {
Object attrCompanyName = request.getAttribute(WebFrameworkUtils.HEADER_VISIT_COMPANY_NAME);
if (attrCompanyName instanceof String) {
companyName = (String) attrCompanyName;
} else if (loginUser != null) {
companyName = loginUser.getVisitCompanyName();
}
}
Long deptId = WebFrameworkUtils.getDeptId(request);
// 部门信息同样遵循“请求头 -> 请求属性 -> 登录缓存”的回退顺序
if (deptId == null || deptId <= 0L) {
Long attrDeptId = resolveLong(request.getAttribute(WebFrameworkUtils.HEADER_VISIT_DEPT_ID));
if (attrDeptId != null && attrDeptId > 0L) {
deptId = attrDeptId;
} else if (loginUser != null && loginUser.getVisitDeptId() != null && loginUser.getVisitDeptId() > 0L) {
deptId = loginUser.getVisitDeptId();
}
}
String deptName = WebFrameworkUtils.getDeptName(request);
if (deptName == null || deptName.isEmpty()) {
Object attrDeptName = request.getAttribute(WebFrameworkUtils.HEADER_VISIT_DEPT_NAME);
if (attrDeptName instanceof String) {
deptName = (String) attrDeptName;
} else if (loginUser != null) {
deptName = loginUser.getVisitDeptName();
}
}
if (companyId == null || companyId <= 0L) {
CompanyContextHolder.setIgnore(true);
return true;
}
Long deptId = WebFrameworkUtils.getDeptId(request);
String deptName = WebFrameworkUtils.getDeptName(request);
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
CompanyContextHolder.setIgnore(false);
CompanyContextHolder.setCompanyId(companyId);
if (loginUser == null) {
return true;
}
if (deptId > 0L) {
// 同步最新的访问公司/部门到登录用户对象,供后续数据权限及上下文读取
loginUser.setVisitCompanyId(companyId);
loginUser.setVisitCompanyName(companyName);
if (deptId != null && deptId > 0L) {
loginUser.setVisitDeptId(deptId);
loginUser.setVisitDeptName(deptName);
}
// if (!securityFrameworkService.hasAnyPermissions(PERMISSION)) {
// throw exception0(GlobalErrorCodeConstants.FORBIDDEN.getCode(), "您无权切换部门");
// }
loginUser.setVisitCompanyId(companyId);
loginUser.setVisitCompanyName(companyName);
CompanyContextHolder.setCompanyId(companyId);
return true;
}
@@ -55,4 +93,18 @@ public class CompanyVisitContextInterceptor implements HandlerInterceptor {
loginUser.setVisitCompanyId(0L);
}
}
private Long resolveLong(Object value) {
if (value instanceof Number) {
return ((Number) value).longValue();
}
if (value instanceof String) {
try {
return Long.parseLong(((String) value).trim());
} catch (NumberFormatException ignored) {
return null;
}
}
return null;
}
}