|
|
@ -1,22 +1,11 @@ |
|
|
|
/** |
|
|
|
* Copyright (c) 2018 人人开源 All rights reserved. |
|
|
|
* <p> |
|
|
|
* https://www.renren.io
|
|
|
|
* <p> |
|
|
|
* 版权所有,侵权必究! |
|
|
|
*/ |
|
|
|
|
|
|
|
package com.epmet.commons.mybatis.aspect; |
|
|
|
|
|
|
|
import com.epmet.commons.mybatis.annotation.DataFilter; |
|
|
|
import com.epmet.commons.mybatis.feign.MybatisGovAccessFeignClient; |
|
|
|
import com.epmet.commons.tools.constant.AccessSettingConstant; |
|
|
|
import com.epmet.commons.tools.constant.OpeScopeConstant; |
|
|
|
import com.epmet.commons.mybatis.dto.form.*; |
|
|
|
import com.epmet.commons.tools.constant.ThreadLocalConstant; |
|
|
|
import com.epmet.commons.tools.dto.form.LoginUserInfoResultDTO; |
|
|
|
import com.epmet.commons.tools.exception.EpmetErrorCode; |
|
|
|
import com.epmet.commons.tools.exception.RenException; |
|
|
|
import com.epmet.commons.tools.security.user.LoginUserUtil; |
|
|
|
import com.epmet.commons.tools.utils.Result; |
|
|
|
import org.apache.commons.lang3.ArrayUtils; |
|
|
|
import org.apache.commons.lang3.StringUtils; |
|
|
@ -28,9 +17,6 @@ import org.slf4j.Logger; |
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
import org.springframework.stereotype.Component; |
|
|
|
import org.springframework.util.CollectionUtils; |
|
|
|
|
|
|
|
import java.util.*; |
|
|
|
|
|
|
|
/** |
|
|
|
* 数据过滤,切面处理类 |
|
|
@ -44,13 +30,11 @@ public class DataFilterAspect { |
|
|
|
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(DataFilterAspect.class); |
|
|
|
|
|
|
|
/** |
|
|
|
* 线程变量,记录是否已经添加了至少一个过滤条件 |
|
|
|
*/ |
|
|
|
private static final ThreadLocal<Boolean> hasConditions = new ThreadLocal(); |
|
|
|
@Autowired |
|
|
|
private LoginUserUtil loginUserUtil; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private MybatisGovAccessFeignClient govAccessFeignClient; |
|
|
|
private MybatisGovAccessFeignClient mybatisGovAccessFeignClient; |
|
|
|
|
|
|
|
@Before("@annotation(com.epmet.commons.mybatis.annotation.DataFilter)") |
|
|
|
public void dataFilter(JoinPoint point) { |
|
|
@ -88,22 +72,17 @@ public class DataFilterAspect { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
LoginUserInfoResultDTO loginUserInfo = ThreadLocalConstant.loginUserInfoTl.get(); |
|
|
|
//LoginUserInfoResultDTO loginUserInfo = getLoginUserInfo();
|
|
|
|
|
|
|
|
hasConditions.set(false); |
|
|
|
|
|
|
|
// 生成过滤sql
|
|
|
|
String sqlFilterSegment = getSqlFilterSegment( |
|
|
|
loginUserInfo.getUserId(), |
|
|
|
loginUserInfo.getRoleIdList(), |
|
|
|
requirePermission, |
|
|
|
loginUserInfo.getOrgIdPath(), |
|
|
|
loginUserInfo.getGridIdList(), |
|
|
|
tableAlias, |
|
|
|
loginUserInfo.getDeptIdList(), |
|
|
|
gridId, |
|
|
|
deptId, |
|
|
|
requirePermission); |
|
|
|
GetSQLFilterFormDTO form = new GetSQLFilterFormDTO(); |
|
|
|
form.setApp(loginUserUtil.getLoginUserApp()); |
|
|
|
form.setClient(loginUserUtil.getLoginUserClient()); |
|
|
|
form.setUserId(loginUserUtil.getLoginUserId()); |
|
|
|
form.setDepartmentId(deptId); |
|
|
|
form.setGridId(gridId); |
|
|
|
form.setOperationKey(requirePermission); |
|
|
|
form.setTableAlias(tableAlias); |
|
|
|
Result<String> sqlFilterSegmentRst = mybatisGovAccessFeignClient.getSqlFilterSegment(form); |
|
|
|
|
|
|
|
// 方式1.填充到Service方法列表中的DataScope对象中。如果dao入参是用DTO的话,那么再加一个DataScope入参,sql中会报错提示#{}参数找不到,因此改用方法2
|
|
|
|
//Object[] methodArgs = point.getArgs();
|
|
|
@ -115,319 +94,13 @@ public class DataFilterAspect { |
|
|
|
//}
|
|
|
|
|
|
|
|
// 方式2,采用ThreadLocal传参到DataFilterInterceptor中
|
|
|
|
if (StringUtils.isNotBlank(sqlFilterSegment)) { |
|
|
|
ThreadLocalConstant.sqlFilter.set(sqlFilterSegment); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 生成过滤sql片段 |
|
|
|
* |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
private String getSqlFilterSegment(String userId, Set<String> roleIds, String reqiurePermission, String orgIdPath, |
|
|
|
Set<String> gridIdList, String tableAlias, Set<String> deptIds, String gridId, String deptId, |
|
|
|
String operationKey) { |
|
|
|
|
|
|
|
StringBuilder sb = new StringBuilder(); |
|
|
|
|
|
|
|
Map<String, String> accessSettings = listRoleAccessSettings(roleIds, operationKey); |
|
|
|
|
|
|
|
// 1.生成sql:组织范围过滤
|
|
|
|
if (!genOrgScopeSql(sb, orgIdPath, roleIds, reqiurePermission, tableAlias)) { |
|
|
|
// 返回false,说明已经开启了all所有范围,后续条件不在拼接入sql,结束执行
|
|
|
|
return sb.toString(); |
|
|
|
} |
|
|
|
|
|
|
|
// 2.生成sql:我发起的
|
|
|
|
String iCreated = accessSettings.get(AccessSettingConstant.I_CREATED_KEY); |
|
|
|
if (StringUtils.isNotBlank(iCreated) && AccessSettingConstant.I_CREATED_ON.equals(iCreated)) { |
|
|
|
genICreatedSql(sb, userId, tableAlias); |
|
|
|
} |
|
|
|
|
|
|
|
// 3.生成sql:本网格的
|
|
|
|
String inGrid = accessSettings.get(AccessSettingConstant.IN_GRID_KEY); |
|
|
|
if (StringUtils.isNotBlank(inGrid) && AccessSettingConstant.IN_GRID_ON.equals(inGrid)) { |
|
|
|
if (StringUtils.isBlank(gridId)) { |
|
|
|
log.error("DataFilter:拼接SQL语句出错:需要in grid权限,但是代码中没有获取到:{}", gridId); |
|
|
|
throw new RenException(EpmetErrorCode.SERVER_ERROR.getCode()); |
|
|
|
} |
|
|
|
genInGrid(sb, gridId, tableAlias); |
|
|
|
} |
|
|
|
|
|
|
|
// 4.生成sql:根据部门列表
|
|
|
|
String inDept = accessSettings.get(AccessSettingConstant.IN_DEPARTMENT_KEY); |
|
|
|
if (StringUtils.isNotBlank(inDept) && AccessSettingConstant.IN_DEPARTMENT_ON.equals(inDept)) { |
|
|
|
if (StringUtils.isBlank(deptId)) { |
|
|
|
log.error("DataFilter:拼接SQL语句出错:需要in department权限,但是代码中没有获取到:{}", deptId); |
|
|
|
throw new RenException(EpmetErrorCode.SERVER_ERROR.getCode()); |
|
|
|
} |
|
|
|
genDepartmentFilterSql(sb, deptId, tableAlias); |
|
|
|
if (!sqlFilterSegmentRst.success()) { |
|
|
|
throw new RenException("DataFilterAspect调用Access服务生成SqlFilterSegment失败:" + sqlFilterSegmentRst.getMsg()); |
|
|
|
} |
|
|
|
|
|
|
|
return sb.toString(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 列出角色对应的权限设置项 |
|
|
|
* |
|
|
|
* @param roleIds |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
private Map<String, String> listRoleAccessSettings(Set<String> roleIds, String operationKey) { |
|
|
|
Map<String, String> settings = new HashMap<>(); |
|
|
|
roleIds.forEach(roleId -> { |
|
|
|
settings.putAll(listRoleAccessSettings(roleId, operationKey)); |
|
|
|
}); |
|
|
|
return settings; |
|
|
|
} |
|
|
|
|
|
|
|
private Map<String, String> listRoleAccessSettings(String roleId, String operationKey) { |
|
|
|
AccessSettingFormDTO accessSettingFormDTO = new AccessSettingFormDTO(); |
|
|
|
accessSettingFormDTO.setRoleId(roleId); |
|
|
|
accessSettingFormDTO.setOperationKey(operationKey); |
|
|
|
Result<Map<String, String>> result = govAccessFeignClient.listAccessSettings(accessSettingFormDTO); |
|
|
|
if (result.success()) { |
|
|
|
return result.getData(); |
|
|
|
} else { |
|
|
|
log.error("角色[{}]查询权限配置AccessSettings失败:{}", roleId, result.getMsg()); |
|
|
|
} |
|
|
|
return new HashMap<>(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 生成部门过滤sql |
|
|
|
* |
|
|
|
* @param sb |
|
|
|
*/ |
|
|
|
private void genDepartmentFilterSql(StringBuilder sb, String deptId, String tableAlias) { |
|
|
|
//Result<List<DepartmentListResultDTO>> deptListResult = govOrgFeignClient.getDepartmentListByStaffId(staffId);
|
|
|
|
if (hasConditions.get()) { |
|
|
|
// 之前没有条件
|
|
|
|
sb.append(" OR "); |
|
|
|
} |
|
|
|
if (StringUtils.isBlank(tableAlias)) { |
|
|
|
sb.append(" DEPARTMENT_ID = '").append(deptId).append("' "); |
|
|
|
} else { |
|
|
|
sb.append(" ").append(tableAlias).append(".DEPARTMENT_ID ='").append(deptId).append("' "); |
|
|
|
} |
|
|
|
hasConditions.set(true); |
|
|
|
} |
|
|
|
|
|
|
|
//private void genDepartmentFilterSql(StringBuilder sb, Set<String> deptIdList) {
|
|
|
|
// //Result<List<DepartmentListResultDTO>> deptListResult = govOrgFeignClient.getDepartmentListByStaffId(staffId);
|
|
|
|
// if (CollectionUtils.isEmpty(deptIdList)) {
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
// deptIdList.forEach(deptId -> {
|
|
|
|
// sb.append(hasConditions.get() ? " OR " : "").append(" DEPARTMENT_ID = '").append(deptId).append("' ");
|
|
|
|
// });
|
|
|
|
// hasConditions.set(true);
|
|
|
|
//}
|
|
|
|
|
|
|
|
/** |
|
|
|
* 网格sql |
|
|
|
* |
|
|
|
* @param sb |
|
|
|
* @param tableAlias |
|
|
|
*/ |
|
|
|
private void genInGrid(StringBuilder sb, String gridId, String tableAlias) { |
|
|
|
if (hasConditions.get()) { |
|
|
|
// 之前没有条件
|
|
|
|
sb.append(" OR "); |
|
|
|
} |
|
|
|
|
|
|
|
// OR GRID_ID = 'XXX' OR GRID_ID = 'QQQ'
|
|
|
|
if (StringUtils.isBlank(tableAlias)) { |
|
|
|
sb.append(" GRID_ID = '").append(gridId).append("' "); |
|
|
|
} else { |
|
|
|
sb.append(" ").append(tableAlias).append(".GRID_ID ='").append(gridId).append("' "); |
|
|
|
} |
|
|
|
hasConditions.set(true); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* sql:我发起的 |
|
|
|
* |
|
|
|
* @param userId |
|
|
|
*/ |
|
|
|
private void genICreatedSql(StringBuilder sb, String userId, String tableAlias) { |
|
|
|
if (StringUtils.isBlank(tableAlias)) { |
|
|
|
sb.append(hasConditions.get() ? " OR " : " ").append(" CREATED_BY ='").append(userId).append("'"); |
|
|
|
} else { |
|
|
|
sb.append(hasConditions.get() ? " OR " : " ").append(tableAlias).append(".CREATED_BY ='").append(userId).append("'"); |
|
|
|
} |
|
|
|
hasConditions.set(true); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 计算组织范围过滤sql,整体入口 |
|
|
|
* @param sb |
|
|
|
* @param orgIdPath |
|
|
|
* @param roleIds |
|
|
|
* @param reqiurePermission |
|
|
|
* @param tableAlias |
|
|
|
* @return Boolean 是否继续往下执行。true:继续执行,false:不继续执行 |
|
|
|
*/ |
|
|
|
public boolean genOrgScopeSql(StringBuilder sb, String orgIdPath, Set<String> roleIds, String reqiurePermission, String tableAlias) { |
|
|
|
|
|
|
|
// 根据角色列表查询操作范围列表
|
|
|
|
Set<RoleOpeScopeResultDTO> opeAndScopes = new HashSet<>(); |
|
|
|
|
|
|
|
roleIds.forEach(roleId -> { |
|
|
|
Result<List<RoleOpeScopeResultDTO>> opeResult = govAccessFeignClient.listRoleAllOperationScopesByRoleId(roleId); |
|
|
|
if (!opeResult.success()) { |
|
|
|
log.error("DataFilter:根据角色查询角色所有的操作列表出错:{}", opeResult.getMsg()); |
|
|
|
} else { |
|
|
|
List<RoleOpeScopeResultDTO> opes = opeResult.getData(); |
|
|
|
if (!CollectionUtils.isEmpty(opes)) { |
|
|
|
opes.forEach(ope -> { |
|
|
|
if (reqiurePermission.equals(ope.getOperationKey())) { |
|
|
|
// 拿到当前操作对应的 RoleOpeScopeResultDTO
|
|
|
|
opeAndScopes.add(ope); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 过滤出最大的范围
|
|
|
|
HashSet<String> scopes = filteScopes(opeAndScopes); |
|
|
|
if (CollectionUtils.isEmpty(scopes)) { |
|
|
|
// 没有范围限制
|
|
|
|
return true; |
|
|
|
} |
|
|
|
if (scopes.contains(OpeScopeConstant.ORG_ALL)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// 生成sql语句
|
|
|
|
genOrgScopeSql(sb, scopes, orgIdPath, tableAlias); |
|
|
|
sb.replace(sb.lastIndexOf("OR"), sb.lastIndexOf("OR") + 3, ""); |
|
|
|
hasConditions.set(true); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 计算组织范围过滤sql |
|
|
|
* PS:这个方法需要优化,当前阶段因为逻辑不稳定,暂时不做过度封装 |
|
|
|
* @param scopes |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
private void genOrgScopeSql(StringBuilder sb, HashSet<String> scopes, String orgIdPath, String tableAlias) { |
|
|
|
// 取出父组织ID path 和当前组织ID
|
|
|
|
//String parentOrgIDPath = orgIdPath.substring(0, orgIdPath.lastIndexOf(orgIdPathSpliter));
|
|
|
|
//String currOrgID = orgIdPath.substring(orgIdPath.lastIndexOf(orgIdPathSpliter) + 1);
|
|
|
|
|
|
|
|
for (String scope : scopes) { |
|
|
|
switch (scope) { |
|
|
|
// 当前单位(可以用ORG_ID_PATH,也可以用ORG_ID判断)
|
|
|
|
case OpeScopeConstant.ORG_CURR: |
|
|
|
if (StringUtils.isBlank(tableAlias)) { |
|
|
|
sb.append(" ORG_ID_PATH = '").append(orgIdPath).append("' OR "); |
|
|
|
//sb.append(" ORG_ID = '").append(currOrgID).append("' OR ");
|
|
|
|
} else { |
|
|
|
sb.append(" ").append(tableAlias).append(".ORG_ID_PATH = '").append(orgIdPath).append("' OR "); |
|
|
|
//sb.append(" ").append(tableAlias).append(".ORG_ID = '").append(currOrgID).append("' OR ");
|
|
|
|
} |
|
|
|
break; |
|
|
|
// 本单位及其子级单位
|
|
|
|
case OpeScopeConstant.ORG_CURR_AND_SUB: |
|
|
|
if (StringUtils.isBlank(tableAlias)) { |
|
|
|
sb.append(" ORG_ID_PATH like '").append(orgIdPath).append("%' OR "); |
|
|
|
} else { |
|
|
|
sb.append(" ").append(tableAlias).append(".ORG_ID_PATH like '").append(orgIdPath).append("%' OR "); |
|
|
|
} |
|
|
|
break; |
|
|
|
// 本单位的子级单位
|
|
|
|
case OpeScopeConstant.ORG_CURR_SUB: |
|
|
|
if (StringUtils.isBlank(tableAlias)) { |
|
|
|
sb.append(" ORG_ID_PATH like '").append(orgIdPath).append(":%' OR "); |
|
|
|
} else { |
|
|
|
sb.append(" ").append(tableAlias).append(".ORG_ID_PATH like '").append(orgIdPath).append(":%' OR "); |
|
|
|
} |
|
|
|
break; |
|
|
|
//当前单位的父级单位
|
|
|
|
case OpeScopeConstant.ORG_CURR_SUP: |
|
|
|
if (StringUtils.isBlank(tableAlias)) { |
|
|
|
sb.append(" '").append(orgIdPath).append("' like CONCAT(").append("ORG_ID_PATH,':%') OR "); |
|
|
|
} else { |
|
|
|
sb.append(" '").append(orgIdPath).append("' like CONCAT(").append(tableAlias).append(".ORG_ID_PATH,':%') OR "); |
|
|
|
} |
|
|
|
break; |
|
|
|
// 当前单位及其父级单位
|
|
|
|
case OpeScopeConstant.ORG_CURR_AND_SUP: |
|
|
|
if (StringUtils.isBlank(tableAlias)) { |
|
|
|
sb.append(" '").append(orgIdPath).append("' like CONCAT(").append("ORG_ID_PATH,'%') OR "); |
|
|
|
} else { |
|
|
|
sb.append(" '").append(orgIdPath).append("' like CONCAT(").append(tableAlias).append(".ORG_ID_PATH,'%' ) OR "); |
|
|
|
} |
|
|
|
break; |
|
|
|
case OpeScopeConstant.ORG_EQUAL: |
|
|
|
// todo 同级
|
|
|
|
//sb.append(" OR ");
|
|
|
|
break; |
|
|
|
case OpeScopeConstant.ORG_EQUAL_AND_SUB: |
|
|
|
// todo 同级及其子级
|
|
|
|
//sb.append(" OR ");
|
|
|
|
break; |
|
|
|
case OpeScopeConstant.ORG_EQUAL_SUB: |
|
|
|
// todo 同级的子级
|
|
|
|
//sb.append(" OR ");
|
|
|
|
break; |
|
|
|
case OpeScopeConstant.ORG_EQUAL_AND_SUP: |
|
|
|
// todo 同级及其上级
|
|
|
|
//sb.append(" OR ");
|
|
|
|
break; |
|
|
|
case OpeScopeConstant.ORG_EQUAL_SUP: |
|
|
|
// todo 同级的上级
|
|
|
|
//sb.append(" OR ");
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 过滤有效范围 |
|
|
|
* |
|
|
|
* @param scopeDTOS |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
private HashSet<String> filteScopes(Set<RoleOpeScopeResultDTO> scopeDTOS) { |
|
|
|
HashMap<String, RoleOpeScopeResultDTO> filtedScopes = new HashMap<>(); |
|
|
|
for (RoleOpeScopeResultDTO scope : scopeDTOS) { |
|
|
|
String scopeIndex = scope.getScopeIndex(); |
|
|
|
if (StringUtils.isBlank(scopeIndex)) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (OpeScopeConstant.ORG_ALL.equals(scope.getScopeKey())) { |
|
|
|
// 该操作具有all的权限,直接放入
|
|
|
|
filtedScopes.put(scopeIndex, scope); |
|
|
|
break; |
|
|
|
} |
|
|
|
String[] currArr = scopeIndex.split("_"); |
|
|
|
if ("0".equals(currArr[1])) { |
|
|
|
// 为0,说明没有包含关系,直接放入
|
|
|
|
filtedScopes.put(scopeIndex, scope); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
RoleOpeScopeResultDTO tempScope = filtedScopes.get(currArr[0]); |
|
|
|
if (tempScope != null) { |
|
|
|
// 已经有ac开头的了
|
|
|
|
String tempScopeIndex = tempScope.getScopeIndex(); |
|
|
|
if (Integer.valueOf(currArr[1]) < Integer.valueOf(tempScopeIndex.split("_")[1])) { |
|
|
|
filtedScopes.put(currArr[0], scope); |
|
|
|
} |
|
|
|
} else { |
|
|
|
filtedScopes.put(currArr[0], scope); |
|
|
|
} |
|
|
|
} |
|
|
|
HashSet<String> scopeStrs = new HashSet<>(); |
|
|
|
Set<Map.Entry<String, RoleOpeScopeResultDTO>> entries = filtedScopes.entrySet(); |
|
|
|
for (Map.Entry<String, RoleOpeScopeResultDTO> entry : entries) { |
|
|
|
scopeStrs.add(entry.getValue().getScopeKey()); |
|
|
|
if (StringUtils.isNotBlank(sqlFilterSegmentRst.getData())) { |
|
|
|
ThreadLocalConstant.sqlFilter.set(sqlFilterSegmentRst.getData()); |
|
|
|
} |
|
|
|
return scopeStrs; |
|
|
|
} |
|
|
|
} |
|
|
|