feat(tenant): 实现 ProjectSecurityWebFilter 项目权限集合校验
新增 ProjectSecurityWebFilter: - 集合校验: user.authorizedProjectIds.contains(header.projectId) - 默认项目选择: DEFAULT编码 → 最小ID → 单项目自动选中 → 无授权403 - @ProjectIgnore URL 自动跳过 - 注册在 WebFilterOrderEnum.PROJECT_SECURITY_FILTER (-98) 框架层: - ProjectCommonApi: 新增 getAuthorizedProjectIds, getDefaultProjectId - ProjectFrameworkService: 新增授权查询 + Caffeine 缓存(60s/1000条) - ViewshTenantAutoConfiguration: 注册 Filter + 扫描 @ProjectIgnore 业务层: - ProjectService: 新增 getAuthorizedProjectIds, getDefaultProjectId - ProjectServiceImpl: 默认项目3级回退逻辑 - ProjectApiImpl: 实现 Feign 端点 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,4 +31,14 @@ public class ProjectApiImpl implements ProjectCommonApi {
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<Long>> getAuthorizedProjectIds(Long userId) {
|
||||
return success(projectService.getAuthorizedProjectIds(userId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> getDefaultProjectId(Long userId) {
|
||||
return success(projectService.getDefaultProjectId(userId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -93,4 +93,21 @@ public interface ProjectService {
|
||||
*/
|
||||
Long createDefaultProject(Long tenantId, String tenantName);
|
||||
|
||||
/**
|
||||
* 获得用户授权的项目编号列表
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @return 项目编号列表
|
||||
*/
|
||||
List<Long> getAuthorizedProjectIds(Long userId);
|
||||
|
||||
/**
|
||||
* 获得用户的默认项目编号
|
||||
* 逻辑:1.找 DEFAULT 编码 → 2.取最小 ID → 3.无授权返回 null
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @return 默认项目编号,无授权返回 null
|
||||
*/
|
||||
Long getDefaultProjectId(Long userId);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.viewsh.module.system.service.project;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.viewsh.framework.common.enums.CommonStatusEnum;
|
||||
import com.viewsh.framework.common.pojo.PageResult;
|
||||
import com.viewsh.framework.common.util.collection.CollectionUtils;
|
||||
@@ -138,6 +139,33 @@ public class ProjectServiceImpl implements ProjectService {
|
||||
return project.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> getAuthorizedProjectIds(Long userId) {
|
||||
List<UserProjectDO> userProjects = userProjectMapper.selectListByUserId(userId);
|
||||
return CollectionUtils.convertList(userProjects, UserProjectDO::getProjectId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getDefaultProjectId(Long userId) {
|
||||
List<Long> authorizedProjectIds = getAuthorizedProjectIds(userId);
|
||||
if (CollUtil.isEmpty(authorizedProjectIds)) {
|
||||
return null;
|
||||
}
|
||||
// 1. 只有一个项目,直接返回
|
||||
if (authorizedProjectIds.size() == 1) {
|
||||
return authorizedProjectIds.get(0);
|
||||
}
|
||||
// 2. 查找 DEFAULT 项目
|
||||
for (Long projectId : authorizedProjectIds) {
|
||||
ProjectDO project = projectMapper.selectById(projectId);
|
||||
if (project != null && ProjectDO.CODE_DEFAULT.equals(project.getCode())) {
|
||||
return project.getId();
|
||||
}
|
||||
}
|
||||
// 3. 取最小 ID
|
||||
return authorizedProjectIds.stream().min(Long::compareTo).orElse(null);
|
||||
}
|
||||
|
||||
private void validateProjectExists(Long id) {
|
||||
if (projectMapper.selectById(id) == null) {
|
||||
throw exception(PROJECT_NOT_EXISTS);
|
||||
|
||||
Reference in New Issue
Block a user