权限过滤

This commit is contained in:
2026-06-29 13:12:20 +08:00
parent c22aa559f6
commit 6d12e4e4ef
9 changed files with 357 additions and 18 deletions
@@ -0,0 +1,46 @@
package com.nbport.zgwl.auth;
import org.springframework.stereotype.Component;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 本地模拟 AuthManager。
*
* 目的不是还原正式权限中心,而是把调用方式先固定住:
* authManager.isUserCanAccessSys(userId, SysEnum.BUSINESS/MANAGE)
*
* 后续复制到正式环境时,保留方法签名,替换内部实现即可。
*/
@Component
public class AuthManager {
/**
* 写死几套本地用户可访问系统。
*
* 约定:
* 1L -> 超管,可同时访问 manage / business
* 2L -> manage 侧管理员
* 3L -> business 侧业务管理员
* 4L -> business 侧普通用户
*/
private static final Map<Long, Set<SysEnum>> USER_SYS_ACCESS = new HashMap<>();
static {
USER_SYS_ACCESS.put(1L, EnumSet.of(SysEnum.MANAGE, SysEnum.BUSINESS));
USER_SYS_ACCESS.put(2L, EnumSet.of(SysEnum.MANAGE));
USER_SYS_ACCESS.put(3L, EnumSet.of(SysEnum.BUSINESS));
USER_SYS_ACCESS.put(4L, EnumSet.of(SysEnum.BUSINESS));
}
public boolean isUserCanAccessSys(Long userId, SysEnum sysEnum) {
if (userId == null || sysEnum == null) {
return false;
}
Set<SysEnum> accessSet = USER_SYS_ACCESS.get(userId);
return accessSet != null && accessSet.contains(sysEnum);
}
}
@@ -0,0 +1,32 @@
package com.nbport.zgwl.auth;
import com.nbport.zgwl.entity.SysUserEntity;
import com.nbport.zgwl.utils.AdminSecurityManage;
import org.springframework.stereotype.Component;
import java.util.Set;
/**
* 本地模拟 SecurityManager。
*
* 保持与正式环境接近的方法形态:
* securityManager.isSuperAdmin()
*/
@Component
public class SecurityManager {
private static final Set<Long> SUPER_ADMIN_IDS = Set.of(1L);
private final AdminSecurityManage adminSecurityManage;
public SecurityManager(AdminSecurityManage adminSecurityManage) {
this.adminSecurityManage = adminSecurityManage;
}
public boolean isSuperAdmin() {
SysUserEntity currentUser = adminSecurityManage.getUser();
return currentUser != null
&& currentUser.getId() != null
&& SUPER_ADMIN_IDS.contains(currentUser.getId());
}
}
@@ -0,0 +1,13 @@
package com.nbport.zgwl.auth;
/**
* 本地模拟系统枚举。
*
* 正式环境里你已有同名/同义枚举时,
* 这里的调用方式可以直接平移过去。
*/
public enum SysEnum {
MANAGE,
BUSINESS
}
@@ -43,6 +43,9 @@ public interface ContractLaunchMapper {
/** 根据主键查询合同 */
ContractLaunchDto selectContractById(@Param("id") Long id);
/** 根据主键并带权限条件查询合同 */
ContractLaunchDto selectContractByIdWithScope(@Param("id") Long id, @Param("query") ContractLaunchQueryDto queryDto);
/** 根据 contractSysId 查询合同(法务回调时用于定位) */
ContractLaunchDto selectContractByContractSysId(@Param("contractSysId") String contractSysId);
@@ -2,6 +2,9 @@ package com.nbport.zgwl.contractlaunch.service;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nbport.zgwl.auth.AuthManager;
import com.nbport.zgwl.auth.SecurityManager;
import com.nbport.zgwl.auth.SysEnum;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nbport.zgwl.common.PageResult;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchApproveDto;
@@ -49,6 +52,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Locale;
import java.util.UUID;
import java.util.stream.Collectors;
@@ -68,6 +72,8 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
private final ContractLaunchMapper contractLaunchMapper;
private final AdminSecurityManage adminSecurityManage;
private final AuthManager authManager;
private final SecurityManager securityManager;
private final SettlementPushService settlementPushService;
private final DataCollectionPushService dataCollectionPushService;
private final ContractLaunchLegalFileBridgeService legalFileBridgeService;
@@ -94,11 +100,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
@Override
public PageResult<ContractLaunchDto> queryPage(ContractLaunchQueryDto queryDto) {
SysUserEntity currentUser = adminSecurityManage.getUser();
String scope = resolveQueryScope(currentUser);
queryDto.setQueryScope(scope);
queryDto.setCurrentUserId(currentUser.getUsername());
queryDto.setCurrentOrgId(currentUser.getSysOrgEntity() == null ? null : currentUser.getSysOrgEntity().getId());
queryDto.setCurrentDeptName(currentUser.getSysOrgEntity() == null ? null : currentUser.getSysOrgEntity().getOrgName());
applyQueryScope(queryDto, currentUser);
Page<ContractLaunchDto> page = new Page<>(queryDto.getPageNo(), queryDto.getPageSize());
Page<ContractLaunchDto> resultPage = (Page<ContractLaunchDto>) contractLaunchMapper.selectContractPage(page, queryDto);
PageResult<ContractLaunchDto> pageResult = new PageResult<>(resultPage);
@@ -117,13 +119,31 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
* 当前无角色体系,暂统一返回 admin(即不过滤),保证流程可跑通。
*/
private String resolveQueryScope(SysUserEntity currentUser) {
if (currentUser == null || currentUser.getId() == null) {
return "personal";
}
if (securityManager.isSuperAdmin()) {
return "admin";
}
String permissionScope = resolveScopeByDataPermission(currentUser.getDataPermission());
if (permissionScope != null) {
return permissionScope;
}
if (authManager.isUserCanAccessSys(currentUser.getId(), SysEnum.MANAGE)) {
return isAdminUser(currentUser) ? "company" : "personal";
}
if (authManager.isUserCanAccessSys(currentUser.getId(), SysEnum.BUSINESS)) {
return isAdminUser(currentUser) ? "company" : "personal";
}
return "personal";
}
/** 查询详情,含日志 */
@Override
public ContractLaunchDto getDetail(Long id) {
ContractLaunchDto contract = contractLaunchMapper.selectContractById(id);
SysUserEntity currentUser = adminSecurityManage.getUser();
ContractLaunchQueryDto queryDto = buildScopeQuery(currentUser);
ContractLaunchDto contract = contractLaunchMapper.selectContractByIdWithScope(id, queryDto);
if (contract == null) {
throw new ServiceException("合同不存在");
}
@@ -1973,4 +1993,52 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
private String trim(String value) {
return value == null ? null : value.trim();
}
private void applyQueryScope(ContractLaunchQueryDto queryDto, SysUserEntity currentUser) {
ContractLaunchQueryDto scopeQuery = buildScopeQuery(currentUser);
queryDto.setQueryScope(scopeQuery.getQueryScope());
queryDto.setCurrentUserId(scopeQuery.getCurrentUserId());
queryDto.setCurrentOrgId(scopeQuery.getCurrentOrgId());
queryDto.setCurrentDeptName(scopeQuery.getCurrentDeptName());
}
private ContractLaunchQueryDto buildScopeQuery(SysUserEntity currentUser) {
ContractLaunchQueryDto queryDto = new ContractLaunchQueryDto();
queryDto.setQueryScope(resolveQueryScope(currentUser));
queryDto.setCurrentUserId(currentUser == null ? null : currentUser.getUsername());
queryDto.setCurrentOrgId(currentUser == null || currentUser.getSysOrgEntity() == null
? null
: currentUser.getSysOrgEntity().getId());
queryDto.setCurrentDeptName(currentUser == null
? null
: (currentUser.getDeptName() == null || currentUser.getDeptName().isBlank()
? (currentUser.getSysOrgEntity() == null ? null : currentUser.getSysOrgEntity().getOrgName())
: currentUser.getDeptName()));
return queryDto;
}
private boolean isAdminUser(SysUserEntity currentUser) {
return currentUser != null && Objects.equals(currentUser.getAdminFlag(), 1L);
}
private String resolveScopeByDataPermission(String dataPermission) {
String value = trim(dataPermission);
if (value == null || value.isBlank()) {
return null;
}
String normalized = value.toUpperCase(Locale.ROOT);
if (normalized.contains("ALL") || normalized.contains("ADMIN") || normalized.contains("全部")) {
return "admin";
}
if (normalized.contains("COMPANY") || normalized.contains("ORG") || normalized.contains("公司")) {
return "company";
}
if (normalized.contains("DEPT") || normalized.contains("DEPARTMENT") || normalized.contains("部门")) {
return "department";
}
if (normalized.contains("SELF") || normalized.contains("PERSONAL") || normalized.contains("个人")) {
return "personal";
}
return null;
}
}
@@ -8,6 +8,8 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
@Data
@TableName(value = "sys_user")
@@ -29,6 +31,36 @@ public class SysUserEntity extends BaseEntity<SysUserEntity> {
@TableField("email")
private String email;
/**
* 本地模拟正式环境字段:是否管理员。
* 约定:1-管理员,0-普通用户
*/
@TableField(exist = false)
private Long adminFlag;
/**
* 本地模拟正式环境字段:部门名称。
*/
@TableField(exist = false)
private String deptName;
/**
* 本地模拟正式环境字段:数据权限。
*
* 可取:
* ALL / COMPANY / DEPARTMENT / SELF
*/
@TableField(exist = false)
private String dataPermission;
/**
* 当前用户手机号/账号之外的本地模拟角色编码。
*
* 保留这个字段仅用于本地调试扩展,正式环境可忽略。
*/
@TableField(exist = false)
private List<String> roleCodes = new ArrayList<>();
/**
* 当前登录人的所属组织
*
@@ -2,8 +2,12 @@ package com.nbport.zgwl.utils;
import com.nbport.zgwl.entity.SysOrgEntity;
import com.nbport.zgwl.entity.SysUserEntity;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 登录用户获取组件
*
@@ -14,10 +18,116 @@ import org.springframework.stereotype.Component;
@Component
public class AdminSecurityManage {
private static final String HEADER_MOCK_USER = "X-Mock-User";
private final HttpServletRequest request;
private final String defaultMockUser;
public AdminSecurityManage(HttpServletRequest request,
@Value("${mock.security.current-user:admin}") String defaultMockUser) {
this.request = request;
this.defaultMockUser = defaultMockUser;
}
public SysUserEntity getUser() {
String mockUser = request == null ? null : request.getHeader(HEADER_MOCK_USER);
if (mockUser == null || mockUser.isBlank()) {
mockUser = defaultMockUser;
}
if ("manage_admin".equalsIgnoreCase(mockUser)) {
return buildManageAdmin();
}
if ("business_admin".equalsIgnoreCase(mockUser)) {
return buildBusinessAdmin();
}
if ("business_user".equalsIgnoreCase(mockUser)) {
return buildBusinessUser();
}
return buildSuperAdmin();
}
private SysUserEntity buildSuperAdmin() {
return buildUser(
1L,
"admin",
"13800000000",
"admin@test.com",
buildOrg("1", "浙江海港物流集团有限公司X"),
"平台管理部",
1L,
"ALL",
List.of("SUPER_ADMIN", "MANAGE_ADMIN", "BUSINESS_ADMIN")
);
}
private SysUserEntity buildManageAdmin() {
return buildUser(
2L,
"manage_admin",
"13800000001",
"manage_admin@test.com",
buildOrg("1", "浙江海港物流集团有限公司X"),
"财务部",
1L,
"COMPANY",
List.of("MANAGE_ADMIN")
);
}
private SysUserEntity buildBusinessAdmin() {
return buildUser(
3L,
"business_admin",
"13800000002",
"business_admin@test.com",
buildOrg("384", "江苏远洋新世纪2供应链有限公司"),
"业务一部",
1L,
"COMPANY",
List.of("BUSINESS_ADMIN")
);
}
private SysUserEntity buildBusinessUser() {
return buildUser(
4L,
"business_user",
"13800000003",
"business_user@test.com",
buildOrg("384", "江苏远洋新世纪2供应链有限公司"),
"业务一部",
0L,
"SELF",
List.of("BUSINESS_USER")
);
}
private SysUserEntity buildUser(Long id,
String username,
String mobilePhone,
String email,
SysOrgEntity orgEntity,
String deptName,
Long adminFlag,
String dataPermission,
List<String> roleCodes) {
SysUserEntity user = new SysUserEntity();
user.setId(id);
user.setUsername(username);
user.setMobilePhone(mobilePhone);
user.setEmail(email);
user.setSysOrgEntity(orgEntity);
user.setDeptName(deptName);
user.setAdminFlag(adminFlag);
user.setDataPermission(dataPermission);
user.setRoleCodes(roleCodes);
return user;
}
private SysOrgEntity buildOrg(String orgId, String orgName) {
SysOrgEntity orgEntity = new SysOrgEntity();
orgEntity.setId("1");
orgEntity.setOrgName("浙江海港物流集团有限公司X");
orgEntity.setId(orgId);
orgEntity.setOrgName(orgName);
orgEntity.setContactPhone("13800000000");
orgEntity.setContactEmail("admin@test.com");
orgEntity.setContactAddress("宁波市北仑区明州路288号");
@@ -26,14 +136,7 @@ public class AdminSecurityManage {
orgEntity.setBankAccount("330201000000000001");
orgEntity.setLegalRepresentative("张三");
orgEntity.setCreditCode("91330200MAZGWL0001");
orgEntity.setInvoiceTitleOptions(java.util.List.of("浙港物流平台有限公司"));
SysUserEntity user = new SysUserEntity();
user.setId(1L);
user.setUsername("admin");
user.setMobilePhone("13800000000");
user.setEmail("admin@test.com");
user.setSysOrgEntity(orgEntity);
return user;
orgEntity.setInvoiceTitleOptions(List.of("浙港物流平台有限公司"));
return orgEntity;
}
}
+5
View File
@@ -11,6 +11,11 @@ spring:
hikari:
connection-test-query: SELECT 1 FROM DUAL
mock:
security:
# 可选:admin / manage_admin / business_admin / business_user
current-user: admin
# 合同推送 —— 测试环境地址
contract-push:
settlement:
@@ -318,6 +318,43 @@
and IS_DELETED = 'N'
</select>
<select id="selectContractByIdWithScope" resultMap="ContractLaunchResult">
<include refid="mainColumns"/>
<where>
ID = #{id}
and IS_DELETED = 'N'
<if test="query.queryScope != null and query.queryScope != '' and query.queryScope != 'admin'">
and (
<choose>
<when test="query.queryScope == 'personal'">
CREATE_BY = #{query.currentUserId}
</when>
<when test="query.queryScope == 'department'">
INITIATOR_DEPT = #{query.currentDeptName}
</when>
<when test="query.queryScope == 'company'">
ORG_ID = #{query.currentOrgId}
</when>
</choose>
<if test="query.currentOrgId != null and query.currentOrgId != ''">
or INSTR(',' || SIGNING_SUBJECT_CODE || ',', ',' || #{query.currentOrgId} || ',') &gt; 0
</if>
<if test="query.currentOrgId != null and query.currentOrgId != ''">
or ID in (
select p.CONTRACT_ID
from SEAL_CONTRACT_LAUNCH_PARTY p
inner join ILDM_FEE_CUSTOMER_INFO c on p.PARTNER_ID = c.CUSTOMER_SYSID
where p.IS_DELETED = 'N'
and p.ROLE_CODE = 'OPPOSITE'
and c.LINKED_ORG_ID is not null
and TO_CHAR(c.LINKED_ORG_ID) = #{query.currentOrgId}
)
</if>
)
</if>
</where>
</select>
<select id="selectContractByContractSysId" resultMap="ContractLaunchResult">
<include refid="mainColumns"/>
where CONTRACT_SYS_ID = #{contractSysId}