zhouhao 8 rokov pred
rodič
commit
47ebcbc6da

+ 1 - 17
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/Authorize.java

@@ -75,22 +75,6 @@ public @interface Authorize {
      */
     String message() default "{unauthorized}";
 
-    /**
-     * 表达式验证
-     *
-     * @return 表达式
-     * @see RequiresExpression#value()
-     */
-    String expression() default "";
-
-    /**
-     * 表达式语言,默认spring表达式
-     *
-     * @return 表达式语言
-     * @see RequiresExpression#language()
-     */
-    String expressionLanguage() default "spel";
-
     /**
      * 是否合并类上的注解
      *
@@ -103,6 +87,6 @@ public @interface Authorize {
      *
      * @return logical
      */
-    Logical logical() default Logical.OR;
+    Logical logical() default Logical.DEFAULT;
 
 }

+ 1 - 1
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/Logical.java

@@ -18,5 +18,5 @@
 package org.hswebframework.web.authorization.annotation;
 
 public enum Logical {
-    AND,OR
+    AND, OR, DEFAULT
 }

+ 3 - 4
hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/ListenerAuthorizingRealm.java

@@ -76,10 +76,9 @@ public class ListenerAuthorizingRealm extends AuthorizingRealm implements UserAu
                         .stream()
                         .map(permission -> {
                             StringBuilder builder = new StringBuilder(permission.getId());
-                            builder.append(":*")
-                                    .append(permission.getActions().isEmpty() ? "" : ",")
-                                    .append(permission.getActions().stream()
-                                            .reduce((a1, a2) -> a1.concat(",").concat(a2)));
+                            builder.append(permission.getActions().stream()
+                                    .reduce((a1, a2) -> a1.concat(",").concat(a2))
+                                    .orElse(""));
                             return new WildcardPermission(builder.toString());
                         }).collect(Collectors.toList()));
 

+ 1 - 1
hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/ShiroAutoconfiguration.java

@@ -209,7 +209,7 @@ public class ShiroAutoconfiguration {
         @ResponseStatus(HttpStatus.UNAUTHORIZED)
         @ResponseBody
         ResponseMessage handleException(UnauthenticatedException exception) {
-            return ResponseMessage.error("{access_denied}", 401);
+            return ResponseMessage.error(exception.getMessage() == null ? "{access_denied}" : exception.getMessage(), 401);
         }
     }
 

+ 5 - 0
hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/boost/BoostAuthorizationAttributeSourceAdvisor.java

@@ -63,9 +63,14 @@ public class BoostAuthorizationAttributeSourceAdvisor extends StaticMethodMatche
     public BoostAuthorizationAttributeSourceAdvisor(DataAccessController dataAccessController,
                                                     FieldAccessController fieldAccessController) {
         AopAllianceAnnotationsAuthorizingMethodInterceptor interceptor = new AopAllianceAnnotationsAuthorizingMethodInterceptor();
+        // @RequiresExpression support
         interceptor.getMethodInterceptors().add(new ExpressionAnnotationMethodInterceptor());
+        // @RequiresDataAccess support
         interceptor.getMethodInterceptors().add(new DataAccessAnnotationMethodInterceptor(dataAccessController));
+        // @RequiresFieldAccess support
         interceptor.getMethodInterceptors().add(new FieldAccessAnnotationMethodInterceptor(fieldAccessController));
+        // @Authorize support
+        interceptor.getMethodInterceptors().add(new SimpleAuthorizeMethodInterceptor());
         setAdvice(interceptor);
     }
 

+ 175 - 0
hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/boost/SimpleAuthorizeMethodInterceptor.java

@@ -0,0 +1,175 @@
+/*
+ *  Copyright 2016 http://www.hswebframework.org
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *
+ */
+
+package org.hswebframework.web.authorization.shiro.boost;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.shiro.authz.AuthorizationException;
+import org.apache.shiro.authz.UnauthenticatedException;
+import org.apache.shiro.authz.aop.AuthorizingAnnotationHandler;
+import org.apache.shiro.authz.aop.AuthorizingAnnotationMethodInterceptor;
+import org.hswebframework.expands.script.engine.DynamicScriptEngine;
+import org.hswebframework.expands.script.engine.DynamicScriptEngineFactory;
+import org.hswebframework.web.authorization.Authorization;
+import org.hswebframework.web.authorization.AuthorizationHolder;
+import org.hswebframework.web.authorization.Permission;
+import org.hswebframework.web.authorization.Role;
+import org.hswebframework.web.authorization.annotation.Authorize;
+import org.hswebframework.web.authorization.annotation.Logical;
+import org.hswebframwork.utils.ClassUtils;
+import org.hswebframwork.utils.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.annotation.Annotation;
+import java.util.*;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * 对{@link Authorize} 注解的支持
+ *
+ * @author zhouhao
+ */
+public class SimpleAuthorizeMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {
+    public SimpleAuthorizeMethodInterceptor() {
+        super(new AuthorizeAnnotationHandler());
+    }
+
+    private static final Logger logger = LoggerFactory.getLogger(SimpleAuthorizeMethodInterceptor.class);
+
+    static class AuthorizeAnnotationHandler extends AuthorizingAnnotationHandler {
+
+        public AuthorizeAnnotationHandler() {
+            super(Authorize.class);
+        }
+
+        @Override
+        public void assertAuthorized(Annotation a) throws AuthorizationException {
+            if (!(a instanceof Authorize)) return;
+            MethodInterceptorHolder holder = MethodInterceptorHolder.current();
+            if (null == holder) {
+                return;
+            }
+            AuthorizeConfig authorizeConfig = new AuthorizeConfig(holder.getArgs());
+            Authorize authorize = ((Authorize) a);
+            if (authorize.merge()) {
+                Authorize classAnn = ClassUtils.getAnnotation(holder.getTarget().getClass(), Authorize.class);
+                if (null != classAnn) {
+                    authorizeConfig.put(classAnn);
+                }
+            }
+            authorizeConfig.put(authorize);
+
+            Authorization authorization = AuthorizationHolder.get();
+            if (null == authorization) throw new UnauthenticatedException(authorizeConfig.message);
+            boolean access = true;
+            Logical logical = authorizeConfig.logical == Logical.DEFAULT ? Logical.OR : authorizeConfig.logical;
+            boolean logicalIsOr = logical == Logical.OR;
+            // 控制权限
+            if (!authorizeConfig.permission.isEmpty()) {
+                List<Permission> permissions = authorization.getPermissions().stream()
+                        .filter(permission -> {
+                            // 未持有任何一个权限
+                            if (!authorizeConfig.permission.contains(permission.getId())) return false;
+                            //未配置action
+                            if (authorizeConfig.action.isEmpty())
+                                return true;
+                            //判断action
+                            List<String> actions = permission.getActions()
+                                    .stream()
+                                    .filter(authorizeConfig.action::contains)
+                                    .collect(Collectors.toList());
+                            //如果 控制逻辑是or,则只要过滤结果数量不为0.否则过滤结果数量必须和配置的数量相同
+                            return logicalIsOr ? actions.size() > 0 : actions.size() == permission.getActions().size();
+                        }).collect(Collectors.toList());
+                access = logicalIsOr ? permissions.size() > 0 : permissions.size() == authorizeConfig.permission.size();
+            }
+            //控制角色
+            if (!authorizeConfig.role.isEmpty()) {
+                Function<Predicate<Role>, Boolean> func = logicalIsOr
+                        ? authorization.getRoles().stream()::anyMatch
+                        : authorization.getRoles().stream()::allMatch;
+                access = func.apply(role -> authorizeConfig.role.contains(role.getId()));
+            }
+            //控制用户
+            if (!authorizeConfig.user.isEmpty()) {
+                Function<Predicate<String>, Boolean> func = logicalIsOr
+                        ? authorizeConfig.user.stream()::anyMatch
+                        : authorizeConfig.user.stream()::allMatch;
+                access = func.apply(authorization.getUser().getId()::equals);
+            }
+            if (!access) {
+                throw new AuthorizationException(authorizeConfig.message);
+            }
+        }
+    }
+
+    static class AuthorizeConfig {
+        Set<String>         permission = new LinkedHashSet<>();
+        Set<String>         action     = new LinkedHashSet<>();
+        Set<String>         role       = new LinkedHashSet<>();
+        Set<String>         user       = new LinkedHashSet<>();
+        Logical             logical    = Logical.DEFAULT;
+        String              message    = "unauthorized";
+        Map<String, Object> var        = null;
+
+        public AuthorizeConfig(Map<String, Object> var) {
+            this.var = var;
+        }
+
+        public void put(Authorize authorize) {
+            permission.addAll(tryCompileExpression(authorize.permission()));
+            action.addAll(tryCompileExpression(authorize.action()));
+            role.addAll(tryCompileExpression(authorize.role()));
+            user.addAll(tryCompileExpression(authorize.user()));
+            if (!StringUtils.isNullOrEmpty(authorize.message())) {
+                message = tryCompileExpression(authorize.message());
+            }
+            if (authorize.logical() != Logical.DEFAULT)
+                logical = authorize.logical();
+        }
+
+        public String tryCompileExpression(String express) {
+            if (express.startsWith("${") && express.endsWith("}")) {
+                express = express.substring(2, express.length() - 1);
+                DynamicScriptEngine spelEngine = DynamicScriptEngineFactory.getEngine("spel");
+                String id = DigestUtils.md5Hex(express);
+                try {
+                    if (!spelEngine.compiled(id))
+                        spelEngine.compile(id, express);
+                    return String.valueOf(spelEngine.execute(id, var).getIfSuccess());
+                } catch (Exception e) {
+                    throw new AuthorizationException("系统错误", e);
+                } finally {
+                    //     spelEngine.remove(id);
+                }
+            } else {
+                return express;
+            }
+        }
+
+        public Collection<String> tryCompileExpression(String... expresses) {
+            return Arrays.stream(expresses)
+                    .filter(Objects::nonNull)
+                    .map(this::tryCompileExpression)
+                    .collect(Collectors.toSet());
+        }
+    }
+}

+ 10 - 1
hsweb-examples/hsweb-examples-simple/src/main/java/org/hswebframework/web/example/simple/TestController.java

@@ -1,10 +1,12 @@
 package org.hswebframework.web.example.simple;
 
+import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.apache.shiro.authz.annotation.RequiresUser;
 import org.hswebframework.web.authorization.Authorization;
 import org.hswebframework.web.authorization.AuthorizationHolder;
 import org.hswebframework.web.authorization.Permission;
 import org.hswebframework.web.authorization.annotation.AuthInfo;
+import org.hswebframework.web.authorization.annotation.Authorize;
 import org.hswebframework.web.authorization.annotation.RequiresDataAccess;
 import org.hswebframework.web.authorization.annotation.RequiresFieldAccess;
 import org.hswebframework.web.commons.entity.Entity;
@@ -27,10 +29,17 @@ import java.util.List;
  * @author zhouhao
  */
 @RestController
+@Authorize(permission = "test")
 public class TestController implements QueryController<UserEntity, String, QueryParamEntity> {
 
+    @GetMapping("/test1")
+    @Authorize(action = "query", message = "${'表达式方式'}")
+    public ResponseMessage testSimple(@AuthInfo Authorization authorization) {
+        return ResponseMessage.ok(authorization);
+    }
+
     @GetMapping("/test")
-    @RequiresUser
+    @RequiresPermissions("test:*")
     public ResponseMessage testShiro(@AuthInfo Authorization authorization) {
         return ResponseMessage.ok(authorization);
     }