From 71f3d463c44c24ec64fe3ab570e5813be3551070 Mon Sep 17 00:00:00 2001 From: fit2cloud-chenyw Date: Tue, 25 Jan 2022 14:35:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20api=E6=9D=83=E9=99=90=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E5=8A=9F=E8=83=BD=E4=BB=A5=E5=8F=8A=E4=BB=AA?= =?UTF-8?q?=E8=A1=A8=E6=9D=BF=E5=A2=9E=E5=88=A0=E6=94=B9=E6=9D=83=E9=99=90?= =?UTF-8?q?demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/pom.xml | 6 + .../auth/annotation/DePermission.java | 22 +++ .../auth/annotation/DePermissions.java | 21 ++ .../aop/DePermissionAnnotationHandler.java | 187 ++++++++++++++++++ .../io/dataease/auth/config/F2CRealm.java | 7 +- .../io/dataease/auth/entity/AuthItem.java | 39 ++++ .../dataease/auth/service/ExtAuthService.java | 20 ++ .../auth/service/impl/ExtAuthServiceImpl.java | 99 +++++++++- .../base/mapper/ext/ExtAuthMapper.java | 13 ++ .../base/mapper/ext/ExtAuthMapper.xml | 123 ++++++++++++ .../commons/constants/AuthConstants.java | 12 ++ .../commons/constants/DePermissionType.java | 5 + .../commons/constants/ResourceAuthLevel.java | 35 ++++ .../commons/model/UserPermissionItem.java | 16 ++ .../io/dataease/commons/utils/AuthUtils.java | 60 +++++- .../panel/PanelGroupController.java | 11 ++ .../controller/sys/SysUserController.java | 9 + .../dataease/plugins/server/XAuthServer.java | 28 ++- .../dataease/plugins/server/XDeptServer.java | 8 + .../dataease/plugins/server/XRoleServer.java | 5 + .../dataease/service/sys/SysUserService.java | 6 + .../src/main/resources/ehcache/ehcache.xml | 168 +++++++++++++--- 22 files changed, 861 insertions(+), 39 deletions(-) create mode 100644 backend/src/main/java/io/dataease/auth/annotation/DePermission.java create mode 100644 backend/src/main/java/io/dataease/auth/annotation/DePermissions.java create mode 100644 backend/src/main/java/io/dataease/auth/aop/DePermissionAnnotationHandler.java create mode 100644 backend/src/main/java/io/dataease/auth/entity/AuthItem.java create mode 100644 backend/src/main/java/io/dataease/commons/constants/DePermissionType.java create mode 100644 backend/src/main/java/io/dataease/commons/constants/ResourceAuthLevel.java create mode 100644 backend/src/main/java/io/dataease/commons/model/UserPermissionItem.java diff --git a/backend/pom.xml b/backend/pom.xml index 2ec6c7ff5e..3f92f3552e 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -22,6 +22,12 @@ + + junit + junit + test + + com.google.guava guava diff --git a/backend/src/main/java/io/dataease/auth/annotation/DePermission.java b/backend/src/main/java/io/dataease/auth/annotation/DePermission.java new file mode 100644 index 0000000000..8524f5e902 --- /dev/null +++ b/backend/src/main/java/io/dataease/auth/annotation/DePermission.java @@ -0,0 +1,22 @@ +package io.dataease.auth.annotation; + +import io.dataease.commons.constants.DePermissionType; +import io.dataease.commons.constants.ResourceAuthLevel; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface DePermission { + + DePermissionType type(); + + ResourceAuthLevel level() default ResourceAuthLevel.COMMON_LEVEL_USE; + + String value() default ""; + + int paramIndex() default 0; +} diff --git a/backend/src/main/java/io/dataease/auth/annotation/DePermissions.java b/backend/src/main/java/io/dataease/auth/annotation/DePermissions.java new file mode 100644 index 0000000000..ceac7a42ca --- /dev/null +++ b/backend/src/main/java/io/dataease/auth/annotation/DePermissions.java @@ -0,0 +1,21 @@ +package io.dataease.auth.annotation; + + +import org.apache.shiro.authz.annotation.Logical; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface DePermissions { + + DePermission[] value(); + + Logical logical() default Logical.AND; + + + +} diff --git a/backend/src/main/java/io/dataease/auth/aop/DePermissionAnnotationHandler.java b/backend/src/main/java/io/dataease/auth/aop/DePermissionAnnotationHandler.java new file mode 100644 index 0000000000..5bc267b60d --- /dev/null +++ b/backend/src/main/java/io/dataease/auth/aop/DePermissionAnnotationHandler.java @@ -0,0 +1,187 @@ +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.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; +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; + +@Aspect +@Component +public class DePermissionAnnotationHandler { + + @Around(value = "@annotation(io.dataease.auth.annotation.DePermissions)") + public Object PermissionsAround(ProceedingJoinPoint point) { + try { + MethodSignature ms = (MethodSignature) point.getSignature(); + Method method = ms.getMethod(); + DePermissions annotation = method.getAnnotation(DePermissions.class); + Logical logical = annotation.logical(); + DePermission[] dePermissions = annotation.value(); + Object[] args = point.getArgs(); + if (logical == Logical.AND) { + for (int i = 0; i < dePermissions.length; i++) { + DePermission permission = dePermissions[i]; + boolean currentAccess = access(args[permission.paramIndex()], permission, 0); + if (!currentAccess) { + return null; + } + } + } else { + List exceptions = new ArrayList<>(); + Boolean someAccess = false; + for (int i = 0; i < dePermissions.length; i++) { + DePermission permission = dePermissions[i]; + try{ + boolean currentAccess = access(args[permission.paramIndex()], permission, 0); + if (currentAccess) { + someAccess = true; + break; + } + }catch (Exception e) { + exceptions.add(e); + } + } + if (!someAccess) { + throw exceptions.get(0); + } + } + return point.proceed(point.getArgs()); + } catch (Throwable throwable) { + LogUtil.error(throwable.getMessage(), throwable); + throw new RuntimeException(throwable); + } + } + + @Around(value = "@annotation(io.dataease.auth.annotation.DePermission)") + public Object PermissionAround(ProceedingJoinPoint point) { + try { + MethodSignature ms = (MethodSignature) point.getSignature(); + Method method = ms.getMethod(); + + DePermission annotation = method.getAnnotation(DePermission.class); + Object arg = point.getArgs()[annotation.paramIndex()]; + if (access(arg, annotation, 0)) { + return point.proceed(point.getArgs()); + } + return false; + + } catch (Throwable throwable) { + LogUtil.error(throwable.getMessage(), throwable); + throw new RuntimeException(throwable); + } + } + + private Boolean access(Object arg, DePermission annotation, int layer) throws Exception { + if (ObjectUtils.isEmpty(arg)) return true; + String type = annotation.type().name().toLowerCase(); + String value = annotation.value(); + Integer requireLevel = annotation.level().getLevel(); + + Set resourceIds = AuthUtils.permissionByType(type).stream().filter( + item -> item.getLevel() >= requireLevel + ).map(AuthItem::getAuthSource).collect(Collectors.toSet()); + + Class parameterType = arg.getClass(); + if (parameterType.isPrimitive() || isWrapClass(parameterType) || 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)) { + for (int i = 0; i < Array.getLength(arg); i++) { + Object o = Array.get(arg, i); + if (!access(o, annotation, layer)) { + return false; + } + } + + } else if (isCollection(parameterType)) { + Object[] array = ((Collection) arg).toArray(); + for (int i = 0; i < array.length; i++) { + Object o = array[i]; + if (!access(o, annotation, layer)) { + return false; + } + } + } else if (isMap(parameterType)) { + Map argMap = (Map) arg; + String[] values = value.split("."); + Object o = argMap.get(values[layer]); + return access(o, annotation, ++layer); + } else { + //当作自定义类处理 + String[] values = value.split("u002E"); + String fieldName = values[layer]; + + Object fieldValue = 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())); + } + + +} diff --git a/backend/src/main/java/io/dataease/auth/config/F2CRealm.java b/backend/src/main/java/io/dataease/auth/config/F2CRealm.java index 6fb27a854d..f89be749a8 100644 --- a/backend/src/main/java/io/dataease/auth/config/F2CRealm.java +++ b/backend/src/main/java/io/dataease/auth/config/F2CRealm.java @@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -44,11 +45,11 @@ public class F2CRealm extends AuthorizingRealm { //验证资源权限 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { - Long userId = JWTUtils.tokenInfoByToken(principals.toString()).getUserId(); + CurrentUserDto userDto = (CurrentUserDto)principals.getPrimaryPrincipal(); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); - Set role = new HashSet<>(authUserService.roles(userId)); + Set role = new HashSet<>(userDto.getRoles().stream().map(item -> ( item.getId() + "")).collect(Collectors.toSet())); simpleAuthorizationInfo.addRoles(role); - Set permission = new HashSet<>(authUserService.permissions(userId)); + Set permission = new HashSet<>(userDto.getPermissions()); simpleAuthorizationInfo.addStringPermissions(permission); return simpleAuthorizationInfo; } diff --git a/backend/src/main/java/io/dataease/auth/entity/AuthItem.java b/backend/src/main/java/io/dataease/auth/entity/AuthItem.java new file mode 100644 index 0000000000..d6790853f3 --- /dev/null +++ b/backend/src/main/java/io/dataease/auth/entity/AuthItem.java @@ -0,0 +1,39 @@ +package io.dataease.auth.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Objects; + +@NoArgsConstructor +@AllArgsConstructor +@Data +public class AuthItem implements Serializable { + + private static final long serialVersionUID = 7909546616315767531L; + + private String authSource; + + private Integer level; + + + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AuthItem authItem = (AuthItem) o; + return Objects.equals(authSource, authItem.authSource) && + Objects.equals(level, authItem.level); + } + + @Override + public int hashCode() { + return Objects.hash(authSource, level); + } + + +} diff --git a/backend/src/main/java/io/dataease/auth/service/ExtAuthService.java b/backend/src/main/java/io/dataease/auth/service/ExtAuthService.java index 7a69be10b3..4b03805972 100644 --- a/backend/src/main/java/io/dataease/auth/service/ExtAuthService.java +++ b/backend/src/main/java/io/dataease/auth/service/ExtAuthService.java @@ -1,7 +1,9 @@ package io.dataease.auth.service; +import io.dataease.auth.entity.AuthItem; import io.dataease.commons.model.AuthURD; +import java.util.List; import java.util.Set; public interface ExtAuthService { @@ -9,4 +11,22 @@ public interface ExtAuthService { Set userIdsByRD(AuthURD request); AuthURD resourceTarget(String resourceId); + + List dataSourceIdByUser(Long userId); + List dataSetIdByUser(Long userId); + List panelIdByUser(Long userId); + + List dataSourceIdByRole(Long roleId); + List dataSetIdByRole(Long roleId); + List panelIdByRole(Long roleId); + + List dataSourceIdByDept(Long deptId); + List dataSetIdByDept(Long deptId); + List panelIdByDept(Long deptId); + + void clearUserResource(Long userId); + void clearDeptResource(Long deptId); + void clearRoleResource(Long roleId); + + } diff --git a/backend/src/main/java/io/dataease/auth/service/impl/ExtAuthServiceImpl.java b/backend/src/main/java/io/dataease/auth/service/impl/ExtAuthServiceImpl.java index 1440e74fd7..f900cd4bc1 100644 --- a/backend/src/main/java/io/dataease/auth/service/impl/ExtAuthServiceImpl.java +++ b/backend/src/main/java/io/dataease/auth/service/impl/ExtAuthServiceImpl.java @@ -1,22 +1,28 @@ package io.dataease.auth.service.impl; +import io.dataease.auth.entity.AuthItem; import io.dataease.auth.service.ExtAuthService; import io.dataease.base.domain.SysAuth; import io.dataease.base.mapper.ext.ExtAuthMapper; +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.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import javax.annotation.Resource; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; @Service public class ExtAuthServiceImpl implements ExtAuthService { + private static final List emptyResult = new ArrayList(); + @Resource private ExtAuthMapper extAuthMapper; @@ -55,4 +61,89 @@ public class ExtAuthServiceImpl implements ExtAuthService { } return authURD; } + + @Cacheable(value = AuthConstants.USER_LINK_NAME, key = "'user' + #userId") + @Override + public List dataSourceIdByUser(Long userId) { + return extAuthMapper.dataSourceIdByUser(userId.toString()); + } + + @Cacheable(value = AuthConstants.USER_DATASET_NAME, key = "'user' + #userId") + @Override + public List dataSetIdByUser(Long userId) { + return extAuthMapper.dataSetIdByUser(userId.toString()); + } + + @Cacheable(value = AuthConstants.USER_PANEL_NAME, key = "'user' + #userId") + @Override + public List panelIdByUser(Long userId) { + return extAuthMapper.panelIdByUser(userId.toString()); + } + + + @Cacheable(value = AuthConstants.ROLE_LINK_NAME, key = "'role' + #roleId") + @Override + public List dataSourceIdByRole(Long roleId) { + return extAuthMapper.dataSourceIdByRole(roleId.toString()); + } + + @Cacheable(value = AuthConstants.ROLE_DATASET_NAME, key = "'role' + #roleId") + @Override + public List dataSetIdByRole(Long roleId) { + return extAuthMapper.dataSetIdByRole(roleId.toString()); + } + + @Cacheable(value = AuthConstants.ROLE_PANEL_NAME, key = "'role' + #roleId") + @Override + public List panelIdByRole(Long roleId) { + return extAuthMapper.panelIdByRole(roleId.toString()); + } + + @Cacheable(value = AuthConstants.DEPT_LINK_NAME, key = "'dept' + #deptId") + @Override + public List dataSourceIdByDept(Long deptId) { + if (ObjectUtils.isEmpty(deptId)) return emptyResult; + return extAuthMapper.dataSourceIdByDept(deptId.toString()); + } + + @Cacheable(value = AuthConstants.DEPT_DATASET_NAME, key = "'dept' + #deptId") + @Override + public List dataSetIdByDept(Long deptId) { + if (ObjectUtils.isEmpty(deptId)) return emptyResult; + return extAuthMapper.dataSetIdByDept(deptId.toString()); + } + + @Cacheable(value = AuthConstants.DEPT_PANEL_NAME, key = "'dept' + #deptId") + @Override + public List panelIdByDept(Long deptId) { + if (ObjectUtils.isEmpty(deptId)) return emptyResult; + return extAuthMapper.panelIdByDept(deptId.toString()); + } + + @Caching(evict = { + @CacheEvict(value = AuthConstants.USER_LINK_NAME, key = "'user' + #userId"), + @CacheEvict(value = AuthConstants.USER_DATASET_NAME, key = "'user' + #userId"), + @CacheEvict(value = AuthConstants.USER_PANEL_NAME, key = "'user' + #userId") + }) + public void clearUserResource(Long userId) { + LogUtil.info("all permission resource of user {} is cleanning...", userId); + } + + @Caching(evict = { + @CacheEvict(value = AuthConstants.DEPT_LINK_NAME, key = "'dept' + #deptId"), + @CacheEvict(value = AuthConstants.DEPT_DATASET_NAME, key = "'dept' + #deptId"), + @CacheEvict(value = AuthConstants.DEPT_PANEL_NAME, key = "'dept' + #deptId") + }) + public void clearDeptResource(Long deptId) { + LogUtil.info("all permission resource of dept {} is cleanning...", deptId); + } + + @Caching(evict = { + @CacheEvict(value = AuthConstants.ROLE_LINK_NAME, key = "'role' + #roleId"), + @CacheEvict(value = AuthConstants.ROLE_DATASET_NAME, key = "'role' + #roleId"), + @CacheEvict(value = AuthConstants.ROLE_PANEL_NAME, key = "'role' + #roleId") + }) + public void clearRoleResource(Long roleId) { + LogUtil.info("all permission resource of role {} is cleanning...", roleId); + } } diff --git a/backend/src/main/java/io/dataease/base/mapper/ext/ExtAuthMapper.java b/backend/src/main/java/io/dataease/base/mapper/ext/ExtAuthMapper.java index 40662c1b59..2f1e8e903c 100644 --- a/backend/src/main/java/io/dataease/base/mapper/ext/ExtAuthMapper.java +++ b/backend/src/main/java/io/dataease/base/mapper/ext/ExtAuthMapper.java @@ -1,6 +1,7 @@ package io.dataease.base.mapper.ext; +import io.dataease.auth.entity.AuthItem; import io.dataease.base.domain.SysAuth; import org.apache.ibatis.annotations.Param; @@ -14,4 +15,16 @@ public interface ExtAuthMapper { List queryUserIdWithDeptIds(@Param("deptIds") List deptIds); List queryByResource(@Param("resourceId") String resourceId); + + List dataSourceIdByUser(String userId); + List dataSetIdByUser(String userId); + List panelIdByUser(String userId); + + List dataSourceIdByRole(String roleId); + List dataSetIdByRole(String roleId); + List panelIdByRole(String roleId); + + List dataSourceIdByDept(String deptId); + List dataSetIdByDept(String deptId); + List panelIdByDept(String deptId); } diff --git a/backend/src/main/java/io/dataease/base/mapper/ext/ExtAuthMapper.xml b/backend/src/main/java/io/dataease/base/mapper/ext/ExtAuthMapper.xml index 8e961576f2..b0498ecded 100644 --- a/backend/src/main/java/io/dataease/base/mapper/ext/ExtAuthMapper.xml +++ b/backend/src/main/java/io/dataease/base/mapper/ext/ExtAuthMapper.xml @@ -2,6 +2,10 @@ + + + + + + + + + + + + + + diff --git a/backend/src/main/java/io/dataease/commons/constants/AuthConstants.java b/backend/src/main/java/io/dataease/commons/constants/AuthConstants.java index 4e06f9216f..2e33f7581c 100644 --- a/backend/src/main/java/io/dataease/commons/constants/AuthConstants.java +++ b/backend/src/main/java/io/dataease/commons/constants/AuthConstants.java @@ -9,4 +9,16 @@ public class AuthConstants { public final static String ID_TOKEN_KEY = "IdToken"; + public final static String USER_LINK_NAME = "user_link"; + public final static String USER_DATASET_NAME = "user_dataset"; + public final static String USER_PANEL_NAME = "user_panel"; + + public final static String ROLE_LINK_NAME = "role_link"; + public final static String ROLE_DATASET_NAME = "role_dataset"; + public final static String ROLE_PANEL_NAME = "role_panel"; + + public final static String DEPT_LINK_NAME = "dept_link"; + public final static String DEPT_DATASET_NAME = "dept_dataset"; + public final static String DEPT_PANEL_NAME = "dept_panel"; + } diff --git a/backend/src/main/java/io/dataease/commons/constants/DePermissionType.java b/backend/src/main/java/io/dataease/commons/constants/DePermissionType.java new file mode 100644 index 0000000000..dd2368d391 --- /dev/null +++ b/backend/src/main/java/io/dataease/commons/constants/DePermissionType.java @@ -0,0 +1,5 @@ +package io.dataease.commons.constants; + +public enum DePermissionType { + DATASOURCE, DATASET, PANEL +} diff --git a/backend/src/main/java/io/dataease/commons/constants/ResourceAuthLevel.java b/backend/src/main/java/io/dataease/commons/constants/ResourceAuthLevel.java new file mode 100644 index 0000000000..4eae45a734 --- /dev/null +++ b/backend/src/main/java/io/dataease/commons/constants/ResourceAuthLevel.java @@ -0,0 +1,35 @@ +package io.dataease.commons.constants; + +public enum ResourceAuthLevel { + + COMMON_LEVEL_USE(1), + + PANNEL_LEVEL_VIEW(1), + PANNEL_LEVEL_EXPORT(3), + PANNEL_LEVEL_MANAGE(5), + PANNEL_LEVEL_GRANT(15), + + DATASET_LEVEL_USE(1), + DATASET_LEVEL_MANAGE(3), + DATASET_LEVEL_GRANT(15), + + LINK_LEVEL_USE(1), + LINK_LEVEL_MANAGE(3), + LINK_LEVEL_GRANT(15); + + private Integer level; + + public Integer getLevel() { + return level; + } + + public void setLevel(Integer level) { + this.level = level; + } + + ResourceAuthLevel(Integer level) { + this.level = level; + } + + +} diff --git a/backend/src/main/java/io/dataease/commons/model/UserPermissionItem.java b/backend/src/main/java/io/dataease/commons/model/UserPermissionItem.java new file mode 100644 index 0000000000..20fc7be962 --- /dev/null +++ b/backend/src/main/java/io/dataease/commons/model/UserPermissionItem.java @@ -0,0 +1,16 @@ +package io.dataease.commons.model; + + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class UserPermissionItem implements Serializable { + + private String type; + + private String resourceId; + + +} diff --git a/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java b/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java index fc349fcebb..5fc77ab5cf 100644 --- a/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java +++ b/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java @@ -1,18 +1,27 @@ package io.dataease.commons.utils; +import io.dataease.auth.api.dto.CurrentRoleDto; import io.dataease.auth.api.dto.CurrentUserDto; +import io.dataease.auth.entity.AuthItem; import io.dataease.auth.service.ExtAuthService; +import io.dataease.commons.constants.ResourceAuthLevel; import io.dataease.commons.model.AuthURD; +import org.apache.commons.lang3.StringUtils; import org.apache.shiro.SecurityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.Set; +import java.util.*; +import java.util.stream.Collectors; @Component public class AuthUtils { + private static final String[] defaultPanelPermissions = {"panel_list"}; + private static final String[] defaultDataSetPermissions = {"0"}; + private static final String[] defaultLinkPermissions = {"0"}; + private static ExtAuthService extAuthService; @Autowired @@ -38,4 +47,53 @@ public class AuthUtils { public static AuthURD authURDR(String resourceId) { return extAuthService.resourceTarget(resourceId); } + + + + public static Set permissionByType(String type) { + CurrentUserDto user = getUser(); + Long userId = user.getUserId(); + Long deptId = user.getDeptId(); + List roles = user.getRoles(); + Set result = new HashSet<>(); + if (StringUtils.equals("link", type)) { + Set userSet = extAuthService.dataSourceIdByUser(userId).stream().collect(Collectors.toSet()); + Set roleSet = roles.stream().map(role -> extAuthService.dataSourceIdByRole(role.getId())).flatMap(Collection::stream).collect(Collectors.toSet()); + Set deptSet = extAuthService.dataSourceIdByDept(deptId).stream().collect(Collectors.toSet()); + result.addAll(userSet); + result.addAll(roleSet); + result.addAll(deptSet); + Arrays.stream(defaultLinkPermissions).forEach(item -> { + result.add(new AuthItem(item, ResourceAuthLevel.LINK_LEVEL_MANAGE.getLevel())); + }); + return result; + } + + else if (StringUtils.equals("dataset", type)) { + Set userSet = extAuthService.dataSetIdByUser(userId).stream().collect(Collectors.toSet()); + Set roleSet = roles.stream().map(role -> extAuthService.dataSetIdByRole(role.getId())).flatMap(Collection::stream).collect(Collectors.toSet()); + Set deptSet = extAuthService.dataSetIdByDept(deptId).stream().collect(Collectors.toSet()); + result.addAll(userSet); + result.addAll(roleSet); + result.addAll(deptSet); + Arrays.stream(defaultDataSetPermissions).forEach(item -> { + result.add(new AuthItem(item, ResourceAuthLevel.DATASET_LEVEL_MANAGE.getLevel())); + }); + return result; + } + else if (StringUtils.equals("panel", type)) { + Set userSet = extAuthService.panelIdByUser(userId).stream().collect(Collectors.toSet()); + Set roleSet = roles.stream().map(role -> extAuthService.panelIdByRole(role.getId())).flatMap(Collection::stream).collect(Collectors.toSet()); + Set deptSet = extAuthService.panelIdByDept(deptId).stream().collect(Collectors.toSet()); + result.addAll(userSet); + result.addAll(roleSet); + result.addAll(deptSet); + Arrays.stream(defaultPanelPermissions).forEach(item -> { + result.add(new AuthItem(item, ResourceAuthLevel.PANNEL_LEVEL_MANAGE.getLevel())); + }); + return result; + } + return result; + + } } diff --git a/backend/src/main/java/io/dataease/controller/panel/PanelGroupController.java b/backend/src/main/java/io/dataease/controller/panel/PanelGroupController.java index d4c2c82725..62383c6c02 100644 --- a/backend/src/main/java/io/dataease/controller/panel/PanelGroupController.java +++ b/backend/src/main/java/io/dataease/controller/panel/PanelGroupController.java @@ -1,14 +1,19 @@ package io.dataease.controller.panel; import com.github.xiaoymin.knife4j.annotations.ApiSupport; +import io.dataease.auth.annotation.DePermission; +import io.dataease.auth.annotation.DePermissions; import io.dataease.base.domain.PanelGroup; import io.dataease.base.domain.PanelGroupWithBLOBs; +import io.dataease.commons.constants.DePermissionType; +import io.dataease.commons.constants.ResourceAuthLevel; import io.dataease.controller.handler.annotation.I18n; import io.dataease.controller.request.panel.PanelGroupRequest; import io.dataease.dto.panel.PanelGroupDTO; import io.dataease.service.panel.PanelGroupService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import org.apache.shiro.authz.annotation.Logical; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; @@ -42,18 +47,24 @@ public class PanelGroupController { @ApiOperation("保存") @PostMapping("/save") + @DePermissions(value = { + @DePermission(type = DePermissionType.PANEL, value = "id"), + @DePermission(type = DePermissionType.PANEL, value = "pid", level = ResourceAuthLevel.PANNEL_LEVEL_MANAGE) + }, logical = Logical.AND) @I18n public PanelGroup saveOrUpdate(@RequestBody PanelGroupRequest request) { return panelGroupService.saveOrUpdate(request); } @ApiOperation("删除") + @DePermission(type = DePermissionType.PANEL, level = ResourceAuthLevel.PANNEL_LEVEL_MANAGE) @PostMapping("/deleteCircle/{id}") public void deleteCircle(@PathVariable String id) { panelGroupService.deleteCircle(id); } @ApiOperation("详细信息") + @DePermission(type = DePermissionType.PANEL, level = ResourceAuthLevel.PANNEL_LEVEL_VIEW) @GetMapping("/findOne/{id}") public PanelGroupWithBLOBs findOne(@PathVariable String id) throws Exception { return panelGroupService.findOne(id); diff --git a/backend/src/main/java/io/dataease/controller/sys/SysUserController.java b/backend/src/main/java/io/dataease/controller/sys/SysUserController.java index 63cf1d1ba8..933f720550 100644 --- a/backend/src/main/java/io/dataease/controller/sys/SysUserController.java +++ b/backend/src/main/java/io/dataease/controller/sys/SysUserController.java @@ -23,6 +23,8 @@ import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.apache.shiro.authz.annotation.RequiresRoles; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; @@ -44,6 +46,7 @@ public class SysUserController { private SysRoleService sysRoleService; @ApiOperation("查询用户") + @RequiresPermissions("user:read") @PostMapping("/userGrid/{goPage}/{pageSize}") @ApiImplicitParams({ @ApiImplicitParam(paramType="path", name = "goPage", value = "页码", required = true, dataType = "Integer"), @@ -57,18 +60,21 @@ public class SysUserController { @ApiOperation("创建用户") + @RequiresPermissions("user:add") @PostMapping("/create") public void create(@RequestBody SysUserCreateRequest request){ sysUserService.save(request); } @ApiOperation("更新用户") + @RequiresPermissions("user:edit") @PostMapping("/update") public void update(@RequestBody SysUserCreateRequest request){ sysUserService.update(request); } @ApiOperation("删除用户") + @RequiresPermissions("user:del") @PostMapping("/delete/{userId}") @ApiImplicitParam(paramType = "path", value = "用户ID", name = "userId", required = true, dataType = "Integer") public void delete(@PathVariable("userId") Long userId){ @@ -77,6 +83,8 @@ public class SysUserController { @ApiOperation("更新用户状态") + @RequiresPermissions("user:edit") + @RequiresRoles("1") @PostMapping("/updateStatus") public void updateStatus(@RequestBody SysUserStateRequest request){ sysUserService.updateStatus(request); @@ -89,6 +97,7 @@ public class SysUserController { sysUserService.updatePwd(request); } @ApiOperation("更新指定用户密码") + @RequiresPermissions("user:editPwd") @PostMapping("/adminUpdatePwd") public void adminUpdatePwd(@RequestBody SysUserPwdRequest request){ sysUserService.adminUpdatePwd(request); diff --git a/backend/src/main/java/io/dataease/plugins/server/XAuthServer.java b/backend/src/main/java/io/dataease/plugins/server/XAuthServer.java index 9282d72b88..012939cda2 100644 --- a/backend/src/main/java/io/dataease/plugins/server/XAuthServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/XAuthServer.java @@ -12,17 +12,19 @@ import io.dataease.plugins.xpack.auth.dto.request.XpackSysAuthRequest; import io.dataease.plugins.xpack.auth.dto.response.XpackSysAuthDetail; import io.dataease.plugins.xpack.auth.dto.response.XpackSysAuthDetailDTO; import io.dataease.plugins.xpack.auth.dto.response.XpackVAuthModelDTO; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.*; import io.dataease.plugins.xpack.auth.service.AuthXpackService; -import java.util.List; -import java.util.Map; -import java.util.Optional; + +import java.util.*; @RequestMapping("/plugin/auth") @RestController public class XAuthServer { + private static final Set cacheTypes = new HashSet<>(); + @PostMapping("/authModels") @I18n public List authModels(@RequestBody XpackBaseTreeRequest request){ @@ -64,6 +66,26 @@ public class XAuthServer { CacheUtils.removeAll(AuthConstants.USER_ROLE_CACHE_NAME); CacheUtils.removeAll(AuthConstants.USER_PERMISSION_CACHE_NAME); } + String authCacheKey = getAuthCacheKey(request); + if (StringUtils.isNotBlank(authCacheKey)) { + CacheUtils.remove(authCacheKey, request.getAuthTargetType() + request.getAuthTarget()); + } }); } + + + private String getAuthCacheKey(XpackSysAuthRequest request) { + if (CollectionUtils.isEmpty(cacheTypes)) { + cacheTypes.add("link"); + cacheTypes.add("dataset"); + cacheTypes.add("panel"); + } + String authTargetType = request.getAuthTargetType(); + String authSourceType = request.getAuthSourceType(); + if (!cacheTypes.contains(authSourceType)) { + return null; + } + return authTargetType + "_" + authSourceType; + + } } diff --git a/backend/src/main/java/io/dataease/plugins/server/XDeptServer.java b/backend/src/main/java/io/dataease/plugins/server/XDeptServer.java index e58fe09995..76dc14c8eb 100644 --- a/backend/src/main/java/io/dataease/plugins/server/XDeptServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/XDeptServer.java @@ -1,6 +1,7 @@ package io.dataease.plugins.server; +import io.dataease.auth.service.ExtAuthService; import io.dataease.commons.utils.BeanUtils; import io.dataease.controller.sys.response.DeptNodeResponse; import io.dataease.plugins.common.entity.XpackGridRequest; @@ -13,6 +14,7 @@ import io.dataease.plugins.xpack.dept.dto.response.XpackSysDept; import io.dataease.plugins.xpack.dept.service.DeptXpackService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; @@ -23,6 +25,9 @@ import java.util.stream.Collectors; @RestController public class XDeptServer { + @Autowired + private ExtAuthService extAuthService; + @ApiOperation("查询子节点") @PostMapping("/childNodes/{pid}") public List childNodes(@PathVariable("pid") Long pid){ @@ -72,6 +77,9 @@ public class XDeptServer { @PostMapping("/delete") public void delete(@RequestBody List requests){ DeptXpackService deptService = SpringContextUtil.getBean(DeptXpackService.class); + requests.forEach(request -> { + extAuthService.clearDeptResource(request.getDeptId()); + }); deptService.batchDelete(requests); } diff --git a/backend/src/main/java/io/dataease/plugins/server/XRoleServer.java b/backend/src/main/java/io/dataease/plugins/server/XRoleServer.java index b9493a0e62..e3ba4da452 100644 --- a/backend/src/main/java/io/dataease/plugins/server/XRoleServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/XRoleServer.java @@ -3,6 +3,7 @@ package io.dataease.plugins.server; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; +import io.dataease.auth.service.ExtAuthService; import io.dataease.commons.utils.PageUtils; import io.dataease.commons.utils.Pager; import io.dataease.plugins.common.entity.XpackGridRequest; @@ -12,6 +13,7 @@ import io.dataease.plugins.xpack.role.dto.response.XpackRoleItemDto; import io.dataease.plugins.xpack.role.service.RoleXpackService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; @@ -21,6 +23,8 @@ import java.util.List; @RestController public class XRoleServer { + @Autowired + private ExtAuthService extAuthService; @ApiOperation("新增角色") @PostMapping("/create") @@ -34,6 +38,7 @@ public class XRoleServer { @PostMapping("/delete/{roleId}") public void delete(@PathVariable("roleId") Long roleId){ RoleXpackService roleXpackService = SpringContextUtil.getBean(RoleXpackService.class); + extAuthService.clearDeptResource(roleId); roleXpackService.delete(roleId); } diff --git a/backend/src/main/java/io/dataease/service/sys/SysUserService.java b/backend/src/main/java/io/dataease/service/sys/SysUserService.java index fc250894ab..2d77f5fb85 100644 --- a/backend/src/main/java/io/dataease/service/sys/SysUserService.java +++ b/backend/src/main/java/io/dataease/service/sys/SysUserService.java @@ -1,6 +1,7 @@ package io.dataease.service.sys; import io.dataease.auth.api.dto.CurrentUserDto; +import io.dataease.auth.service.ExtAuthService; import io.dataease.base.domain.SysUser; import io.dataease.base.domain.SysUserExample; import io.dataease.base.domain.SysUsersRolesExample; @@ -27,6 +28,7 @@ import io.dataease.plugins.xpack.oidc.dto.SSOUserInfo; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.CacheEvict; import org.springframework.stereotype.Service; @@ -54,6 +56,9 @@ public class SysUserService { @Resource private ExtSysUserMapper extSysUserMapper; + @Autowired + private ExtAuthService extAuthService; + public List query(BaseGridRequest request) { @@ -268,6 +273,7 @@ public class SysUserService { @CacheEvict(value = AuthConstants.USER_CACHE_NAME, key = "'user' + #userId") @Transactional public int delete(Long userId) { + extAuthService.clearUserResource(userId); deleteUserRoles(userId); return sysUserMapper.deleteByPrimaryKey(userId); } diff --git a/backend/src/main/resources/ehcache/ehcache.xml b/backend/src/main/resources/ehcache/ehcache.xml index 359ab7483e..3552a6f565 100644 --- a/backend/src/main/resources/ehcache/ehcache.xml +++ b/backend/src/main/resources/ehcache/ehcache.xml @@ -79,7 +79,7 @@ timeToLiveSeconds="60" memoryStoreEvictionPolicy="FIFO" > - + + + + + + + + + + + + + + + + + + + + + + +