Browse Source

优化权限处理逻辑

woody 1 year ago
parent
commit
55ab2961a7

+ 4 - 2
framework-database/src/main/java/com/chelvc/framework/database/interceptor/MybatisConfigureInterceptor.java

@@ -1,5 +1,6 @@
 package com.chelvc.framework.database.interceptor;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -34,7 +35,7 @@ public abstract class MybatisConfigureInterceptor {
     /**
      * 拦截器实例列表
      */
-    private static List<MybatisConfigureInterceptor> INSTANCES = Collections.emptyList();
+    private static final List<MybatisConfigureInterceptor> INSTANCES = Lists.newArrayList();
 
     /**
      * 初始化配置拦截器
@@ -46,7 +47,8 @@ public abstract class MybatisConfigureInterceptor {
                 pool.appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader()));
                 initializeMapperListener(pool);
                 initializeTableInfoListener(pool);
-                INSTANCES = Lists.newArrayList(initializeInterceptorInstances());
+                INSTANCES.addAll(initializeInterceptorInstances());
+                ((ArrayList<MybatisConfigureInterceptor>) INSTANCES).trimToSize();
             } catch (Exception e) {
                 throw new RuntimeException(e);
             } finally {

+ 6 - 13
framework-security/src/main/java/com/chelvc/framework/security/annotation/Permission.java

@@ -7,7 +7,7 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-import com.chelvc.framework.common.util.StringUtils;
+import com.chelvc.framework.security.context.SecurityContextHolder;
 
 /**
  * 自定义权限校验注解
@@ -17,27 +17,20 @@ import com.chelvc.framework.common.util.StringUtils;
  */
 @Inherited
 @Documented
+@Target(ElementType.METHOD)
 @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE, ElementType.METHOD})
 public @interface Permission {
     /**
      * 获取权限标识
      *
      * @return 权限标识
      */
-    String id() default StringUtils.EMPTY;
+    String value();
 
     /**
-     * 获取权限名称
+     * 获取权限分组
      *
-     * @return 权限名称
+     * @return 权限分组
      */
-    String name() default StringUtils.EMPTY;
-
-    /**
-     * 是否启用
-     *
-     * @return true/false
-     */
-    boolean enabled() default true;
+    String group() default SecurityContextHolder.DEFAULT_PERMISSION_GROUP;
 }

+ 53 - 0
framework-security/src/main/java/com/chelvc/framework/security/context/SecurityContextHolder.java

@@ -0,0 +1,53 @@
+package com.chelvc.framework.security.context;
+
+import java.util.Set;
+import java.util.stream.Stream;
+
+import com.chelvc.framework.base.context.ApplicationContextHolder;
+import com.chelvc.framework.base.context.Session;
+import com.chelvc.framework.base.context.SessionContextHolder;
+import com.chelvc.framework.common.util.ObjectUtils;
+import lombok.NonNull;
+
+/**
+ * 应用安全相关操作上下文工具类
+ *
+ * @author Woody
+ * @date 2024/5/24
+ */
+public final class SecurityContextHolder {
+    /**
+     * 默认权限分组
+     */
+    public static final String DEFAULT_PERMISSION_GROUP = "DEFAULT";
+
+    private SecurityContextHolder() {
+    }
+
+    /**
+     * 判断当前用户是否拥有任意权限
+     *
+     * @param permissions 权限标识数组
+     * @return true/false
+     */
+    public static boolean hashAnyPermission(@NonNull String... permissions) {
+        if (ObjectUtils.isEmpty(permissions)) {
+            return true;
+        }
+        Session session = SessionContextHolder.getSession(false);
+        Set<String> authorities = ObjectUtils.ifNull(session, Session::getAuthorities);
+        if (ObjectUtils.notEmpty(authorities)) {
+            Stream<String> stream = Stream.of(permissions);
+            if (stream.anyMatch(authorities::contains)) {
+                return true;
+            }
+            for (String authority : authorities) {
+                Set<?> properties = ApplicationContextHolder.getSafeProperty(authority, Set.class);
+                if (ObjectUtils.notEmpty(properties) && stream.anyMatch(properties::contains)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}

+ 9 - 26
framework-security/src/main/java/com/chelvc/framework/security/interceptor/PermissionValidateInterceptor.java

@@ -1,21 +1,17 @@
 package com.chelvc.framework.security.interceptor;
 
 import java.lang.reflect.Method;
-import java.util.Collections;
 import java.util.List;
 import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import com.chelvc.framework.base.context.ApplicationContextHolder;
-import com.chelvc.framework.base.context.SessionContextHolder;
 import com.chelvc.framework.common.exception.FrameworkException;
 import com.chelvc.framework.common.util.AssertUtils;
 import com.chelvc.framework.common.util.ObjectUtils;
-import com.chelvc.framework.common.util.StringUtils;
 import com.chelvc.framework.security.annotation.Permission;
+import com.chelvc.framework.security.context.SecurityContextHolder;
 import com.google.common.collect.Sets;
 import lombok.RequiredArgsConstructor;
 import org.springframework.aop.framework.AopProxyUtils;
@@ -52,12 +48,7 @@ public class PermissionValidateInterceptor implements ApplicationRunner, Handler
         if (!(handler instanceof HandlerMethod)) {
             return null;
         }
-        HandlerMethod method = (HandlerMethod) handler;
-        Permission annotation = method.getMethodAnnotation(Permission.class);
-        if (annotation == null) {
-            return method.getMethod().getDeclaringClass().getAnnotation(Permission.class);
-        }
-        return annotation;
+        return ((HandlerMethod) handler).getMethodAnnotation(Permission.class);
     }
 
     @Override
@@ -72,12 +63,13 @@ public class PermissionValidateInterceptor implements ApplicationRunner, Handler
             Class<?> clazz = AopProxyUtils.ultimateTargetClass(controller);
             for (Method method : clazz.getDeclaredMethods()) {
                 Permission annotation = method.getAnnotation(Permission.class);
-                if ((annotation == null && (annotation = clazz.getAnnotation(Permission.class)) == null)
-                        || !annotation.enabled()) {
+                if (annotation == null) {
                     continue;
                 }
-                String id = StringUtils.ifEmpty(annotation.id(), method::getName);
-                AssertUtils.check(permissions.add(id), () -> "Permission id duplicated: " + id);
+                String value = annotation.value(), group = annotation.group();
+                AssertUtils.nonempty(value, () -> "Permission value must not be empty: " + method);
+                AssertUtils.nonempty(group, () -> "Permission group must not be empty: " + method);
+                AssertUtils.check(permissions.add(value), () -> "Permission value duplicated: " + value);
             }
         });
     }
@@ -87,17 +79,8 @@ public class PermissionValidateInterceptor implements ApplicationRunner, Handler
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
             throws Exception {
         Permission annotation = this.getPermissionAnnotation(handler);
-        if (annotation == null || !annotation.enabled()) {
-            return true;
-        }
-        Set<String> authorities = SessionContextHolder.getSession().getAuthorities();
-        Set<String> permissions = ObjectUtils.isEmpty(authorities) ? Collections.emptySet() :
-                authorities.stream().flatMap(authority -> {
-                    List<String> ids = ApplicationContextHolder.getSafeProperty(authority, List.class);
-                    return ObjectUtils.isEmpty(ids) ? Stream.empty() : ids.stream();
-                }).collect(Collectors.toSet());
-        String id = StringUtils.ifEmpty(annotation.id(), () -> ((HandlerMethod) handler).getMethod().getName());
-        if (ObjectUtils.isEmpty(permissions) || !permissions.contains(id)) {
+        if (annotation != null &&
+                !SecurityContextHolder.hashAnyPermission(annotation.value(), annotation.group())) {
             throw new FrameworkException(HttpStatus.FORBIDDEN.name(), null,
                     ApplicationContextHolder.getMessage("Forbidden"));
         }