fix: 权限继承模式api权限逻辑调整

This commit is contained in:
fit2cloud-chenyw 2022-04-28 17:49:21 +08:00
parent a3dc2b57c8
commit a2d301b6fa
13 changed files with 236 additions and 85 deletions

View File

@ -10,5 +10,10 @@ import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DeCleaner {
DePermissionType value();
int paramIndex() default 0;
String key() default "";
}

View File

@ -2,73 +2,178 @@ package io.dataease.auth.aop;
import io.dataease.auth.annotation.DeCleaner;
import io.dataease.auth.api.dto.CurrentUserDto;
import io.dataease.auth.util.ReflectUtil;
import io.dataease.commons.constants.AuthConstants;
import io.dataease.commons.constants.DePermissionType;
import io.dataease.commons.model.AuthURD;
import io.dataease.commons.utils.AuthUtils;
import io.dataease.commons.utils.LogUtil;
import io.dataease.listener.util.CacheUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Aspect
@Component
public class DeCleanerAnnotationHandler {
@Around(value = "@annotation(io.dataease.auth.annotation.DeCleaner)")
public Object CleanerAround(ProceedingJoinPoint point) {
@AfterReturning(value = "@annotation(io.dataease.auth.annotation.DeCleaner)")
public void CleanerAround(JoinPoint point) {
try {
MethodSignature ms = (MethodSignature) point.getSignature();
Method method = ms.getMethod();
DeCleaner deCleaner = method.getAnnotation(DeCleaner.class);
DePermissionType type = deCleaner.value();
String key = deCleaner.key();
Object[] args = point.getArgs();
Object paramValue = null;
if (ObjectUtils.isNotEmpty(key) && ArrayUtils.isNotEmpty(args)) {
int pi = deCleaner.paramIndex();
Object arg = point.getArgs()[pi];
paramValue = getParamValue(arg, key, 0);
}
switch (type.name()) {
case "DATASOURCE":
cleanDataSource();
cleanDataSource(paramValue);
break;
case "DATASET":
cleanDataSet();
cleanDataSet(paramValue);
break;
default:
cleanPanel();
cleanPanel(paramValue);
break;
}
return point.proceed(point.getArgs());
} catch (Throwable e) {
LogUtil.error(e.getMessage(), e);
throw new RuntimeException(e);
}
}
public void cleanPanel() {
private void cleanCacheParent(String pid, String type) {
if (StringUtils.isBlank(pid) || StringUtils.isBlank(type)) {
return;
}
CurrentUserDto user = AuthUtils.getUser();
List<String> resourceIds = AuthUtils.parentResources(pid.toString(), type);
if (CollectionUtils.isEmpty(resourceIds))return;
resourceIds.forEach(resourceId -> {
AuthURD authURD = AuthUtils.authURDR(resourceId);
Optional.ofNullable(authURD.getUserIds()).ifPresent(ids -> {
ids.forEach(id -> {
CacheUtils.remove("user_"+type, "user" + id);
});
});
Optional.ofNullable(authURD.getRoleIds()).ifPresent(ids -> {
ids.forEach(id -> {
CacheUtils.remove("role_"+type, "role" + id);
});
});
Optional.ofNullable(authURD.getDeptIds()).ifPresent(ids -> {
ids.forEach(id -> {
List<String> depts = AuthUtils.getAuthModels(id.toString(), "dept", user.getUserId(), user.getIsAdmin());
depts.forEach(deptId -> {
CacheUtils.remove("dept_"+type, "dept" + deptId);
});
});
});
});
}
public void cleanPanel(Object pid) {
CurrentUserDto user = AuthUtils.getUser();
CacheUtils.remove(AuthConstants.USER_PANEL_NAME, "user" + user.getUserId());
CacheUtils.remove(AuthConstants.DEPT_PANEL_NAME, "dept" + user.getDeptId());
user.getRoles().forEach(role -> {
CacheUtils.remove(AuthConstants.ROLE_PANEL_NAME, "role" + role.getId());
});
Optional.ofNullable(pid).ifPresent(resourceId -> {
cleanCacheParent(resourceId.toString(), "panel");
});
}
public void cleanDataSet() {
public void cleanDataSet(Object pid) {
CurrentUserDto user = AuthUtils.getUser();
CacheUtils.remove(AuthConstants.USER_DATASET_NAME, "user" + user.getUserId());
CacheUtils.remove(AuthConstants.DEPT_DATASET_NAME, "dept" + user.getDeptId());
user.getRoles().forEach(role -> {
CacheUtils.remove(AuthConstants.ROLE_DATASET_NAME, "role" + role.getId());
});
Optional.ofNullable(pid).ifPresent(resourceId -> {
cleanCacheParent(resourceId.toString(), "dataset");
});
}
public void cleanDataSource() {
public void cleanDataSource(Object pid) {
CurrentUserDto user = AuthUtils.getUser();
CacheUtils.remove(AuthConstants.USER_LINK_NAME, "user" + user.getUserId());
CacheUtils.remove(AuthConstants.DEPT_LINK_NAME, "dept" + user.getDeptId());
user.getRoles().forEach(role -> {
CacheUtils.remove(AuthConstants.ROLE_LINK_NAME, "role" + role.getId());
});
Optional.ofNullable(pid).ifPresent(resourceId -> {
cleanCacheParent(resourceId.toString(), "link");
});
}
private Object getParamValue(Object arg, String key, int layer) throws Exception{
if (ObjectUtils.isNotEmpty(arg)) return null;
Class<?> parameterType = arg.getClass();
if (parameterType.isPrimitive() || ReflectUtil.isWrapClass(parameterType) || ReflectUtil.isString(parameterType)) {
return arg;
} else if (ReflectUtil.isArray(parameterType)) {
Object result;
for (int i = 0; i < Array.getLength(arg); i++) {
Object o = Array.get(arg, i);
if (ObjectUtils.isNotEmpty((result = getParamValue(o, key, layer)))) {
return result;
}
}
return null;
} else if (ReflectUtil.isCollection(parameterType)) {
Object[] array = ((Collection) arg).toArray();
Object result;
for (int i = 0; i < array.length; i++) {
Object o = array[i];
if (ObjectUtils.isNotEmpty((result = getParamValue(o, key, layer)))) {
return result;
}
}
return null;
} else if (ReflectUtil.isMap(parameterType)) {
Map<String, Object> argMap = (Map) arg;
String[] values = key.split("\\.");
Object o = argMap.get(values[layer]);
return getParamValue(o, key, ++layer);
} else {
// 当作自定义类处理
String[] values = key.split("\\.");
String fieldName = values[layer];
Object fieldValue = ReflectUtil.getFieldValue(arg, values[layer]);
return getParamValue(fieldValue, key, ++layer);
}
}
}

View File

@ -3,10 +3,10 @@ package io.dataease.auth.aop;
import io.dataease.auth.annotation.DePermission;
import io.dataease.auth.annotation.DePermissions;
import io.dataease.auth.entity.AuthItem;
import io.dataease.auth.util.ReflectUtil;
import io.dataease.commons.utils.AuthUtils;
import io.dataease.commons.utils.LogUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.authz.annotation.Logical;
import org.aspectj.lang.ProceedingJoinPoint;
@ -14,9 +14,7 @@ import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
@ -111,13 +109,13 @@ public class DePermissionAnnotationHandler {
item -> item.getLevel() >= requireLevel).map(AuthItem::getAuthSource).collect(Collectors.toSet());
Class<?> parameterType = arg.getClass();
if (parameterType.isPrimitive() || isWrapClass(parameterType) || isString(parameterType)) {
if (parameterType.isPrimitive() || ReflectUtil.isWrapClass(parameterType) || ReflectUtil.isString(parameterType)) {
boolean permissionValid = resourceIds.contains(arg);
if (permissionValid)
return true;
throw new UnauthorizedException("Subject does not have permission[" + annotation.level().name() + ":"
+ annotation.type() + ":" + arg + "]");
} else if (isArray(parameterType)) {
} else if (ReflectUtil.isArray(parameterType)) {
for (int i = 0; i < Array.getLength(arg); i++) {
Object o = Array.get(arg, i);
if (!access(o, annotation, layer)) {
@ -125,7 +123,7 @@ public class DePermissionAnnotationHandler {
}
}
} else if (isCollection(parameterType)) {
} else if (ReflectUtil.isCollection(parameterType)) {
Object[] array = ((Collection) arg).toArray();
for (int i = 0; i < array.length; i++) {
Object o = array[i];
@ -133,7 +131,7 @@ public class DePermissionAnnotationHandler {
return false;
}
}
} else if (isMap(parameterType)) {
} else if (ReflectUtil.isMap(parameterType)) {
Map<String, Object> argMap = (Map) arg;
String[] values = value.split(".");
Object o = argMap.get(values[layer]);
@ -143,59 +141,13 @@ public class DePermissionAnnotationHandler {
String[] values = value.split("\\.");
String fieldName = values[layer];
Object fieldValue = getFieldValue(arg, fieldName);
Object fieldValue = ReflectUtil.getFieldValue(arg, fieldName);
return access(fieldValue, annotation, ++layer);
}
return true;
}
private Object getFieldValue(Object o, String fieldName) throws Exception {
Class<?> aClass = o.getClass();
while (null != aClass.getSuperclass()) {
Field[] declaredFields = aClass.getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
Field field = declaredFields[i];
String name = field.getName();
if (StringUtils.equals(name, fieldName)) {
field.setAccessible(true);
return field.get(o);
}
}
aClass = aClass.getSuperclass();
}
throw new NoSuchFieldException(fieldName);
}
private final static String[] wrapClasies = {
"java.lang.Boolean",
"java.lang.Character",
"java.lang.Integer",
"java.lang.Byte",
"java.lang.Short",
"java.lang.Long",
"java.lang.Float",
"java.lang.Double",
};
private Boolean isString(Class clz) {
return StringUtils.equals("java.lang.String", clz.getName());
}
private Boolean isArray(Class clz) {
return clz.isArray();
}
private Boolean isCollection(Class clz) {
return Collection.class.isAssignableFrom(clz);
}
private Boolean isMap(Class clz) {
return Map.class.isAssignableFrom(clz);
}
private Boolean isWrapClass(Class clz) {
return Arrays.stream(wrapClasies).anyMatch(item -> StringUtils.equals(item, clz.getName()));
}
}

View File

@ -28,5 +28,7 @@ public interface ExtAuthService {
void clearDeptResource(Long deptId);
void clearRoleResource(Long roleId);
List<String> parentResource(String resourceId, String type);
}

View File

@ -8,6 +8,7 @@ import io.dataease.commons.constants.AuthConstants;
import io.dataease.commons.model.AuthURD;
import io.dataease.commons.utils.LogUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
@ -147,6 +148,20 @@ public class ExtAuthServiceImpl implements ExtAuthService {
LogUtil.info("all permission resource of role {} is cleanning...", roleId);
}
@Override
public List<String> parentResource(String resourceId, String type) {
String s = extAuthMapper.parentResource(resourceId, type);
if (StringUtils.isNotBlank(s)) {
String[] split = s.split(",");
List<String> results = new ArrayList<>();
for (int i = 0; i < split.length; i++) {
String s1 = split[i];
if (StringUtils.isNotBlank(s1)) {
results.add(s1);
}
}
return CollectionUtils.isEmpty(results) ? null : results;
}
return null;
}
}

View File

@ -0,0 +1,59 @@
package io.dataease.auth.util;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
public class ReflectUtil {
public static Object getFieldValue(Object o, String fieldName) throws Exception {
Class<?> aClass = o.getClass();
while (null != aClass.getSuperclass()) {
Field[] declaredFields = aClass.getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
Field field = declaredFields[i];
String name = field.getName();
if (StringUtils.equals(name, fieldName)) {
field.setAccessible(true);
return field.get(o);
}
}
aClass = aClass.getSuperclass();
}
throw new NoSuchFieldException(fieldName);
}
private final static String[] wrapClasies = {
"java.lang.Boolean",
"java.lang.Character",
"java.lang.Integer",
"java.lang.Byte",
"java.lang.Short",
"java.lang.Long",
"java.lang.Float",
"java.lang.Double",
};
public static Boolean isString(Class clz) {
return StringUtils.equals("java.lang.String", clz.getName());
}
public static Boolean isArray(Class clz) {
return clz.isArray();
}
public static Boolean isCollection(Class clz) {
return Collection.class.isAssignableFrom(clz);
}
public static Boolean isMap(Class clz) {
return Map.class.isAssignableFrom(clz);
}
public static Boolean isWrapClass(Class clz) {
return Arrays.stream(wrapClasies).anyMatch(item -> StringUtils.equals(item, clz.getName()));
}
}

View File

@ -9,6 +9,10 @@ import io.dataease.commons.constants.DePermissionType;
import io.dataease.commons.constants.ResourceAuthLevel;
import io.dataease.commons.model.AuthURD;
import io.dataease.plugins.config.SpringContextUtil;
import io.dataease.plugins.xpack.auth.dto.request.XpackBaseTreeRequest;
import io.dataease.plugins.xpack.auth.dto.response.XpackVAuthModelDTO;
import io.dataease.plugins.xpack.auth.service.AuthXpackService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
@ -67,6 +71,20 @@ public class AuthUtils {
return userIds;
}
public static List<String> parentResources(String resourceId, String type) {
return extAuthService.parentResource(resourceId, type);
}
public static List<String> getAuthModels(String id, String type, Long userId, Boolean isAdmin) {
AuthXpackService sysAuthService = SpringContextUtil.getBean(AuthXpackService.class);
List<XpackVAuthModelDTO> vAuthModelDTOS = sysAuthService
.searchAuthModelTree(new XpackBaseTreeRequest(id, type, "children"), userId, isAdmin);
List<String> authSources = Optional.ofNullable(vAuthModelDTOS).orElse(new ArrayList<>()).stream()
.map(XpackVAuthModelDTO::getId)
.collect(Collectors.toList());
return authSources;
}
// 获取资源对那些人/角色/组织 有权限
public static AuthURD authURDR(String resourceId) {
return extAuthService.resourceTarget(resourceId);

View File

@ -27,4 +27,6 @@ public interface ExtAuthMapper {
List<AuthItem> dataSourceIdByDept(String deptId);
List<AuthItem> dataSetIdByDept(String deptId);
List<AuthItem> panelIdByDept(String deptId);
String parentResource(@Param("resourceId") String resourceId, @Param("type") String type);
}

View File

@ -152,6 +152,10 @@
GROUP BY a.id
</select>
<select id="parentResource" resultType="String" >
select GET_V_AUTH_MODEL_WITH_PARENT(#{resourceId}, #{type})
</select>
</mapper>

View File

@ -76,7 +76,7 @@ public class XAuthServer {
String authCacheKey = getAuthCacheKey(request);
if (StringUtils.isNotBlank(authCacheKey)) {
if (StringUtils.equals("dept", request.getAuthTargetType())) {
List<String> authTargets = getAuthModels(request.getAuthTarget(), request.getAuthTargetType(),
List<String> authTargets = AuthUtils.getAuthModels(request.getAuthTarget(), request.getAuthTargetType(),
user.getUserId(), user.getIsAdmin());
if (CollectionUtils.isNotEmpty(authTargets)) {
authTargets.forEach(deptId -> {
@ -91,16 +91,6 @@ public class XAuthServer {
});
}
private List<String> getAuthModels(String id, String type, Long userId, Boolean isAdmin) {
AuthXpackService sysAuthService = SpringContextUtil.getBean(AuthXpackService.class);
List<XpackVAuthModelDTO> vAuthModelDTOS = sysAuthService
.searchAuthModelTree(new XpackBaseTreeRequest(id, type, "children"), userId, isAdmin);
List<String> authSources = Optional.ofNullable(vAuthModelDTOS).orElse(new ArrayList<>()).stream()
.map(XpackVAuthModelDTO::getId)
.collect(Collectors.toList());
return authSources;
}
private String getAuthCacheKey(XpackSysAuthRequest request) {
if (CollectionUtils.isEmpty(cacheTypes)) {
cacheTypes.add("link");

View File

@ -44,7 +44,7 @@ public class DataSetGroupService {
@Resource
private SysAuthService sysAuthService;
@DeCleaner(DePermissionType.DATASET)
@DeCleaner(value = DePermissionType.DATASET, key = "pid")
public DataSetGroupDTO save(DatasetGroup datasetGroup) throws Exception {
checkName(datasetGroup);
if (StringUtils.isEmpty(datasetGroup.getId())) {

View File

@ -115,7 +115,7 @@ public class DataSetTableService {
private static Logger logger = LoggerFactory.getLogger(ClassloaderResponsity.class);
@DeCleaner(value = DePermissionType.DATASET)
@DeCleaner(value = DePermissionType.DATASET, key = "sceneId")
public void batchInsert(List<DataSetTableRequest> datasetTable) throws Exception {
for (DataSetTableRequest table : datasetTable) {
save(table);
@ -143,7 +143,7 @@ public class DataSetTableService {
}
}
@DeCleaner(value = DePermissionType.DATASET)
@DeCleaner(value = DePermissionType.DATASET, key = "sceneId")
public void saveExcel(DataSetTableRequest datasetTable) throws Exception {
List<String> datasetIdList = new ArrayList<>();
@ -253,7 +253,7 @@ public class DataSetTableService {
}
}
@DeCleaner(value = DePermissionType.DATASET)
@DeCleaner(value = DePermissionType.DATASET, key = "sceneId")
public DatasetTable save(DataSetTableRequest datasetTable) throws Exception {
checkName(datasetTable);
if (StringUtils.equalsIgnoreCase(datasetTable.getType(), "sql")) {
@ -1847,7 +1847,6 @@ public class DataSetTableService {
return dataSetDetail;
}
@DeCleaner(value = DePermissionType.DATASET)
public ExcelFileData excelSaveAndParse(MultipartFile file, String tableId, Integer editType) throws Exception {
String filename = file.getOriginalFilename();
// parse file

View File

@ -115,7 +115,7 @@ public class PanelGroupService {
return TreeUtils.mergeTree(panelGroupDTOList, "default_panel");
}
@DeCleaner(DePermissionType.PANEL)
@DeCleaner(value = DePermissionType.PANEL, key = "pid")
public PanelGroup saveOrUpdate(PanelGroupRequest request) {
String userName = AuthUtils.getUser().getUsername();
String panelId = request.getId();