requireInstanceVisible 此前只放行提交人/办理人/本校管理员,抄送接收人点开工作台 "抄送我的"行或抄送消息回落链接一律 403——"抄送中心自留、子应用零存储"因此不闭环。 新增 flw_cc 行命中判定(existsByInstanceIdAndUserId,按 instanceId 维度不泛化到本校), 只授予可见、办理权仍在 FlowTaskService 按 assigneeId 复核;中心用户面四处调用点 (详情/进度/出图)自动同口径。embed/url 签发侧 javadoc 同步可见性口径(oapi 层仍只认 schId,用户级判定在子应用后端,跨校与陌生人断言未放宽)。 守卫五态单测:提交人/办理人/管理员/抄送人/陌生人 + 抄送命中范围。
80 lines
3.7 KiB
Java
80 lines
3.7 KiB
Java
package com.yunhai.flowcenter.service;
|
||
|
||
import com.yunhai.flowcenter.entity.FlwInstance;
|
||
import com.yunhai.flowcenter.repository.FlwCcRepository;
|
||
import com.yunhai.flowcenter.repository.FlwTaskRepository;
|
||
import com.yunhai.platform.apistd.BizException;
|
||
import com.yunhai.platform.utils.exception.ErrorCode;
|
||
import com.yunhai.platform.utils.model.BoaUser;
|
||
import lombok.RequiredArgsConstructor;
|
||
import org.springframework.stereotype.Service;
|
||
|
||
import java.util.Arrays;
|
||
import java.util.List;
|
||
|
||
/**
|
||
* 用户面访问守卫(概览 §十):提交人只读写自己办件;办理人只读写分派给自己的任务;
|
||
* 管理员本校可查、不可代批。
|
||
* 2026-10-17(F7 前置补丁):放行口径增「该办件 flw_cc 行接收人」——抄送接收人点开工作台
|
||
* "抄送我的"行或抄送消息回落链接此前一律 403,抄送自留因此不闭环。只读可见,办理权仍按 assigneeId。
|
||
* 管理员口径与 FlowAdminGuard / svc-hall ApplyViewGuard / Notice NoticeFlowGuard 对齐:
|
||
* type==1(超管)或 roleId∈{2,5,7}(校级管理员)——三者必须同口径,否则校级管理员
|
||
* 能列办件却在详情页 403(本类原先只认 type==1,2026-09-14 校正)。
|
||
*/
|
||
@Service
|
||
@RequiredArgsConstructor
|
||
public class FlowAccessGuard {
|
||
|
||
private static final int SUPER_ADMIN_TYPE = 1;
|
||
private static final List<Integer> ADMIN_ROLE_IDS = Arrays.asList(2, 5, 7);
|
||
|
||
private final FlwTaskRepository taskRepository;
|
||
private final FlwCcRepository ccRepository;
|
||
|
||
/** 办件详情可见:提交人本人 / 该办件任务办理人 / 本校管理员(超管或校级管理员)/ 该办件抄送接收人 */
|
||
public void requireInstanceVisible(FlwInstance instance, BoaUser user) {
|
||
if (user == null || user.getId() == null) {
|
||
throw new BizException(ErrorCode.FORBIDDEN, "未登录");
|
||
}
|
||
if (instance.getSubmitterId().equals(user.getId())) {
|
||
return;
|
||
}
|
||
if (!taskRepository.findByInstanceIdOrderByIdAsc(instance.getId()).stream()
|
||
.anyMatch(t -> user.getId().equals(t.getAssigneeId()))) {
|
||
// F7 前置补丁:抄送接收人可读(工作台"抄送我的"行与抄送消息回落链接不再 403)。
|
||
// 只授予可见,办理权仍在 FlowTaskService 按 assigneeId 复核。
|
||
if (!isCcRecipient(instance, user) && !isAdminOf(instance, user)) {
|
||
throw new BizException(ErrorCode.FORBIDDEN, "仅提交人/办理人/本校管理员可查看该办件");
|
||
}
|
||
}
|
||
}
|
||
|
||
/** 该用户是否本办件的抄送接收人(flw_cc 行,逐人一行) */
|
||
private boolean isCcRecipient(FlwInstance instance, BoaUser user) {
|
||
return ccRepository.existsByInstanceIdAndUserId(instance.getId(), user.getId());
|
||
}
|
||
|
||
/**
|
||
* 本校管理员(可查不可代批;办理权在 FlowTaskService 里再按 assigneeId 校验)。
|
||
* 超管与校级管理员均限本校——跨校仍 403,不放大可见范围。
|
||
*/
|
||
private boolean isAdminOf(FlwInstance instance, BoaUser user) {
|
||
Long current = currentSchId(user);
|
||
if (current == null || !current.equals(instance.getSchId())) {
|
||
return false;
|
||
}
|
||
if (user.getType() != null && user.getType() == SUPER_ADMIN_TYPE) {
|
||
return true;
|
||
}
|
||
return user.getRoleIds() != null
|
||
&& user.getRoleIds().stream().anyMatch(r -> r != null && ADMIN_ROLE_IDS.contains(r));
|
||
}
|
||
|
||
private Long currentSchId(BoaUser user) {
|
||
if (user.getCurrentRole() == null || user.getCurrentRole().getSchId() == null) {
|
||
return null;
|
||
}
|
||
return Long.valueOf(user.getCurrentRole().getSchId());
|
||
}
|
||
}
|