Prechádzať zdrojové kódy

新增shiro权限控制

zhouhao 8 rokov pred
rodič
commit
00c5dafce7
13 zmenil súbory, kde vykonal 831 pridanie a 104 odobranie
  1. 28 0
      hsweb-authorization/hsweb-authorization-shiro/pom.xml
  2. 69 0
      hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/CustomAuthenticationToken.java
  3. 104 0
      hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/ListenerAuthorizingRealm.java
  4. 186 0
      hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/ShiroAutoconfiguration.java
  5. 50 0
      hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/ShiroProperties.java
  6. 0 62
      hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/ShiroUserSubject.java
  7. 0 38
      hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/ShiroUserSubjectUtils.java
  8. 117 0
      hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/boost/BoostAuthorizationAttributeSourceAdvisor.java
  9. 81 0
      hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/boost/ExpressionAnnotationMethodInterceptor.java
  10. 78 0
      hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/boost/MethodInterceptorHolder.java
  11. 41 0
      hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/cache/SpringCacheManagerWrapper.java
  12. 76 0
      hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/cache/SpringCacheWrapper.java
  13. 1 4
      hsweb-authorization/hsweb-authorization-shiro/src/test/java/org/hswebframework/web/authorization/shiro/ShiroTests.java

+ 28 - 0
hsweb-authorization/hsweb-authorization-shiro/pom.xml

@@ -48,6 +48,34 @@
             <artifactId>shiro-spring</artifactId>
             <version>${shiro.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjweaver</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hswebframework.web</groupId>
+            <artifactId>hsweb-commons-controller</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+            <version>2.5</version>
+            <optional>true</optional>
+        </dependency>
     </dependencies>
 
 </project>

+ 69 - 0
hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/CustomAuthenticationToken.java

@@ -0,0 +1,69 @@
+/*
+ * 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;
+
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.HostAuthenticationToken;
+import org.apache.shiro.authc.RememberMeAuthenticationToken;
+import org.hswebframework.web.authorization.Authorization;
+
+/**
+ * TODO 完成注释
+ *
+ * @author zhouhao
+ */
+public class CustomAuthenticationToken implements AuthenticationToken, HostAuthenticationToken, RememberMeAuthenticationToken {
+    private Authorization authorization;
+
+    private boolean rememberMe;
+
+    private String host;
+
+    public CustomAuthenticationToken(Authorization authorization, boolean rememberMe) {
+        this.authorization = authorization;
+        this.rememberMe = rememberMe;
+    }
+
+    @Override
+    public Object getPrincipal() {
+        return authorization.getUser().getUsername();
+    }
+
+    @Override
+    public Object getCredentials() {
+        return authorization.getUser().getId();
+    }
+
+    public Authorization getAuthorization() {
+        return authorization;
+    }
+
+    @Override
+    public String getHost() {
+        return null;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    @Override
+    public boolean isRememberMe() {
+        return rememberMe;
+    }
+}

+ 104 - 0
hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/ListenerAuthorizingRealm.java

@@ -0,0 +1,104 @@
+/*
+ * 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;
+
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.authz.permission.WildcardPermission;
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.subject.Subject;
+import org.hswebframework.web.authorization.Authorization;
+import org.hswebframework.web.authorization.Role;
+import org.hswebframework.web.authorization.listener.UserAuthorizationListener;
+
+import java.util.stream.Collectors;
+
+/**
+ * @author zhouhao
+ */
+public class ListenerAuthorizingRealm extends AuthorizingRealm implements UserAuthorizationListener {
+
+    public ListenerAuthorizingRealm() {
+        setAuthenticationTokenClass(CustomAuthenticationToken.class);
+    }
+
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+        String loginName = (String) super.getAvailablePrincipal(principals);
+        return this.<String, AuthorizationInfo>getCache(loginName)
+                .get(AuthorizationInfo.class.getName());
+    }
+
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+        if (token instanceof CustomAuthenticationToken) {
+            return this.<String, AuthenticationInfo>getCache((String) token.getPrincipal())
+                    .get(AuthenticationInfo.class.getName());
+        }
+        throw new AuthenticationException(new UnsupportedOperationException("{token_un_supported}"));
+    }
+
+    private AuthenticationInfo createAuthenticationInfo(Authorization authorization) {
+        return new SimpleAuthenticationInfo(
+                authorization.getUser().getUsername(),
+                authorization.getUser().getId(),
+                authorization.getUser().getName());
+    }
+
+    @Override
+    public void onAuthorizeSuccess(boolean isRemembered, Authorization authorization) {
+        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
+        authorizationInfo.addRoles(authorization.getRoles().stream().map(Role::getId).collect(Collectors.toList()));
+        authorizationInfo.addObjectPermissions(
+                authorization.getPermissions()
+                        .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)));
+                            return new WildcardPermission(builder.toString());
+                        }).collect(Collectors.toList()));
+
+        getCache(authorization.getUser().getUsername())
+                .put(AuthorizationInfo.class.getName(), authorizationInfo);
+
+        getCache(authorization.getUser().getUsername())
+                .put(AuthenticationInfo.class.getName(), createAuthenticationInfo(authorization));
+
+        Subject subject = SecurityUtils.getSubject();
+        subject.login(new CustomAuthenticationToken(authorization, isRemembered));
+        subject.getSession().setAttribute(Authorization.class.getName(), authorization);
+    }
+
+    protected <K, V> Cache<K, V> getCache(String name) {
+        return getCacheManager().getCache(getCacheName(name));
+    }
+
+    protected String getCacheName(String name) {
+        return "shiro.auth.info.".concat(name);
+    }
+}

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

@@ -0,0 +1,186 @@
+/*
+ * 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;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authz.AuthorizationException;
+import org.apache.shiro.authz.UnauthenticatedException;
+import org.apache.shiro.cache.CacheManager;
+import org.apache.shiro.cache.MemoryConstrainedCacheManager;
+import org.apache.shiro.mgt.DefaultSecurityManager;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.session.mgt.DefaultSessionManager;
+import org.apache.shiro.spring.LifecycleBeanPostProcessor;
+import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+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.hswebframework.web.AopUtils;
+import org.hswebframework.web.authorization.Authorization;
+import org.hswebframework.web.authorization.AuthorizationSupplier;
+import org.hswebframework.web.authorization.shiro.boost.BoostAuthorizationAttributeSourceAdvisor;
+import org.hswebframework.web.authorization.shiro.boost.MethodInterceptorHolder;
+import org.hswebframework.web.authorization.shiro.cache.SpringCacheManagerWrapper;
+import org.hswebframework.web.controller.message.ResponseMessage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.util.Collections;
+
+/**
+ * TODO 完成注释
+ *
+ * @author zhouhao
+ */
+@Configuration
+@EnableConfigurationProperties(ShiroProperties.class)
+public class ShiroAutoconfiguration {
+
+    @Autowired(required = false)
+    private org.springframework.cache.CacheManager cacheManager;
+
+    @Autowired
+    private ShiroProperties shiroProperties;
+
+    @Bean
+    public CacheManager shiroCacheManager() {
+        if (cacheManager == null) {
+            return new MemoryConstrainedCacheManager();
+        } else {
+            return new SpringCacheManagerWrapper(cacheManager);
+        }
+    }
+
+    @Bean
+    public ListenerAuthorizingRealm listenerAuthorizingRealm(CacheManager cacheManager) {
+        ListenerAuthorizingRealm realm = new ListenerAuthorizingRealm();
+        realm.setCacheManager(cacheManager);
+        return realm;
+    }
+
+    @Bean(name = "lifecycleBeanPostProcessor")
+    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
+        return new LifecycleBeanPostProcessor();
+    }
+
+    @Bean(name = "securityManager")
+    @ConditionalOnWebApplication
+    public DefaultWebSecurityManager defaultWebSecurityManager(ListenerAuthorizingRealm authorizingRealm) {
+        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+        securityManager.setRealm(authorizingRealm);
+        securityManager.setCacheManager(authorizingRealm.getCacheManager());
+        SecurityUtils.setSecurityManager(securityManager);
+        return securityManager;
+    }
+
+    @Bean(name = "securityManager")
+    @ConditionalOnNotWebApplication
+    public DefaultSecurityManager defaultSecurityManager(ListenerAuthorizingRealm authorizingRealm) {
+        DefaultSecurityManager securityManager = new DefaultSecurityManager();
+        securityManager.setRealm(authorizingRealm);
+        securityManager.setCacheManager(authorizingRealm.getCacheManager());
+        securityManager.setSessionManager(new DefaultSessionManager());
+        SecurityUtils.setSecurityManager(securityManager);
+        return securityManager;
+    }
+
+//    @Bean
+//    @ConditionalOnMissingBean
+//    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
+//        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
+//        advisorAutoProxyCreator.setProxyTargetClass(true);
+//        return advisorAutoProxyCreator;
+//    }
+
+    @Bean
+    public BoostAuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
+        BoostAuthorizationAttributeSourceAdvisor advisor = new BoostAuthorizationAttributeSourceAdvisor();
+        advisor.setSecurityManager(securityManager);
+        return advisor;
+    }
+
+    @Bean
+    public AuthorizationSupplier authorizationSupplier() {
+        return () ->
+                (Authorization) SecurityUtils.getSubject().getSession().getAttribute(Authorization.class.getName());
+    }
+
+    @Bean(name = "shiroFilter")
+    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
+        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
+        // 必须设置 SecurityManager
+        shiroFilterFactoryBean.setSecurityManager(securityManager);
+        if (null != shiroProperties)
+            shiroFilterFactoryBean.setFilterChainDefinitionMap(shiroProperties.getFilters());
+        else
+            shiroFilterFactoryBean.setFilterChainDefinitionMap(Collections.emptyMap());
+        return shiroFilterFactoryBean;
+    }
+
+    @Bean
+    public MethodInterceptorHolderAdvisor methodInterceptorHolderAdvisor() {
+        return new MethodInterceptorHolderAdvisor();
+    }
+
+    @Aspect
+    @Order(Ordered.HIGHEST_PRECEDENCE)
+    static class MethodInterceptorHolderAdvisor {
+        @Around(value = "@annotation(org.hswebframework.web.authorization.annotation.RequiresExpression)")
+        public Object around(ProceedingJoinPoint pjp) throws Throwable {
+            MethodSignature signature = (MethodSignature) pjp.getSignature();
+            String methodName = AopUtils.getMethodName(pjp);
+            String className = pjp.getTarget().getClass().getName();
+            String id = DigestUtils.md5Hex(className.concat(methodName));
+            new MethodInterceptorHolder(id, signature.getMethod(), pjp.getTarget(), AopUtils.getArgsMap(pjp))
+                    .set();
+            return pjp.proceed();
+        }
+    }
+
+    @RestControllerAdvice
+    public static class UnAuthControllerAdvice {
+        @ExceptionHandler(AuthorizationException.class)
+        @ResponseStatus(HttpStatus.FORBIDDEN)
+        @ResponseBody
+        ResponseMessage handleException(AuthorizationException exception) {
+            return ResponseMessage.error(exception.getMessage(), 403);
+        }
+
+        @ExceptionHandler(UnauthenticatedException.class)
+        @ResponseStatus(HttpStatus.UNAUTHORIZED)
+        @ResponseBody
+        ResponseMessage handleException(UnauthenticatedException exception) {
+            return ResponseMessage.error("{access_denied}", 401);
+        }
+    }
+
+}

+ 50 - 0
hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/ShiroProperties.java

@@ -0,0 +1,50 @@
+/*
+ * 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;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.Map;
+
+/**
+ * TODO 完成注释
+ *
+ * @author zhouhao
+ */
+@ConfigurationProperties(prefix = "hsweb.authorize")
+public class ShiroProperties {
+    private Map<String, String> filters;
+
+    private boolean enable = true;
+
+    public Map<String, String> getFilters() {
+        return filters;
+    }
+
+    public void setFilters(Map<String, String> filters) {
+        this.filters = filters;
+    }
+
+    public boolean isEnable() {
+        return enable;
+    }
+
+    public void setEnable(boolean enable) {
+        this.enable = enable;
+    }
+}

+ 0 - 62
hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/ShiroUserSubject.java

@@ -1,62 +0,0 @@
-/*
- *
- *  * 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;
-
-import org.apache.shiro.subject.Subject;
-import org.hswebframework.web.authorization.UserSubject;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * @author zhouhao
- */
-public class ShiroUserSubject implements UserSubject {
-    private Subject subject;
-
-    public ShiroUserSubject(Subject subject) {
-        this.subject = subject;
-    }
-
-    @Override
-    public String getUsername() {
-        return (String) subject.getPrincipal();
-    }
-
-    @Override
-    public boolean hasRoles(Set<String> roles) {
-        return subject.hasAllRoles(roles);
-    }
-
-    @Override
-    public boolean hasRole(String... roleId) {
-        return hasRoles(new HashSet<>(Arrays.asList(roleId)));
-    }
-
-    @Override
-    public boolean hasModule(String moduleId, String... actions) {
-        if (actions.length == 0) return subject.isPermitted(moduleId);
-        String per[] = new String[actions.length];
-        for (int i = 0; i < per.length; i++) {
-            per[i] = moduleId.concat(":").concat(actions[i]);
-        }
-        return subject.isPermittedAll(per);
-    }
-}

+ 0 - 38
hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/ShiroUserSubjectUtils.java

@@ -1,38 +0,0 @@
-/*
- *
- *  * 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;
-
-import org.apache.shiro.SecurityUtils;
-import org.hswebframework.web.authorization.UserSubject;
-import org.hswebframework.web.authorization.UserSubjectUtils;
-
-/**
- * @author zhouhao
- */
-public class ShiroUserSubjectUtils extends UserSubjectUtils {
-
-    @Override
-    public UserSubject getUser() {
-        return new ShiroUserSubject(SecurityUtils.getSubject());
-    }
-
-    public void bind() {
-        UserSubjectUtils.setInstance(this);
-    }
-}

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

@@ -0,0 +1,117 @@
+/*
+ * 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.shiro.authz.annotation.*;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.spring.security.interceptor.AopAllianceAnnotationsAuthorizingMethodInterceptor;
+import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
+import org.hswebframework.web.authorization.annotation.Authorize;
+import org.hswebframework.web.authorization.annotation.RequiresExpression;
+import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
+import org.springframework.core.annotation.AnnotationUtils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+/**
+ * @author zhouhao
+ * @see AuthorizationAttributeSourceAdvisor
+ * @see StaticMethodMatcherPointcutAdvisor
+ */
+public class BoostAuthorizationAttributeSourceAdvisor extends StaticMethodMatcherPointcutAdvisor {
+    @SuppressWarnings("unchecked")
+    private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES =
+            new Class[]{
+                    RequiresPermissions.class, RequiresRoles.class,
+                    RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class,
+                    //自定义
+                    RequiresExpression.class,
+                    Authorize.class
+            };
+
+    protected SecurityManager securityManager = null;
+
+    /**
+     * Create a new AuthorizationAttributeSourceAdvisor.
+     */
+    public BoostAuthorizationAttributeSourceAdvisor() {
+        AopAllianceAnnotationsAuthorizingMethodInterceptor interceptor = new AopAllianceAnnotationsAuthorizingMethodInterceptor();
+        interceptor.getMethodInterceptors().add(new ExpressionAnnotationMethodInterceptor());
+        setAdvice(interceptor);
+    }
+
+    public SecurityManager getSecurityManager() {
+        return securityManager;
+    }
+
+    public void setSecurityManager(org.apache.shiro.mgt.SecurityManager securityManager) {
+        this.securityManager = securityManager;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the method has any Shiro annotations, false otherwise.
+     * The annotations inspected are:
+     * <ul>
+     * <li>{@link org.apache.shiro.authz.annotation.RequiresAuthentication RequiresAuthentication}</li>
+     * <li>{@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser}</li>
+     * <li>{@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest}</li>
+     * <li>{@link org.apache.shiro.authz.annotation.RequiresRoles RequiresRoles}</li>
+     * <li>{@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions}</li>
+     * </ul>
+     *
+     * @param method      the method to check for a Shiro annotation
+     * @param targetClass the class potentially declaring Shiro annotations
+     * @return <tt>true</tt> if the method has a Shiro annotation, false otherwise.
+     * @see org.springframework.aop.MethodMatcher#matches(java.lang.reflect.Method, Class)
+     */
+    public boolean matches(Method method, Class targetClass) {
+        Method m = method;
+
+        if (isAuthzAnnotationPresent(m)) {
+            return true;
+        }
+
+        //The 'method' parameter could be from an interface that doesn't have the annotation.
+        //Check to see if the implementation has it.
+        if (targetClass != null) {
+            try {
+                m = targetClass.getMethod(m.getName(), m.getParameterTypes());
+                if (isAuthzAnnotationPresent(m)) {
+                    return true;
+                }
+            } catch (NoSuchMethodException ignored) {
+                //default return value is false.  If we can't find the method, then obviously
+                //there is no annotation, so just use the default return value.
+            }
+        }
+
+        return false;
+    }
+
+    private boolean isAuthzAnnotationPresent(Method method) {
+        for (Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES) {
+            Annotation a = AnnotationUtils.findAnnotation(method, annClass);
+            if (a != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}

+ 81 - 0
hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/boost/ExpressionAnnotationMethodInterceptor.java

@@ -0,0 +1,81 @@
+/*
+ * 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.shiro.authz.AuthorizationException;
+import org.apache.shiro.authz.aop.AuthorizingAnnotationHandler;
+import org.apache.shiro.authz.aop.AuthorizingAnnotationMethodInterceptor;
+import org.hsweb.expands.script.engine.DynamicScriptEngine;
+import org.hsweb.expands.script.engine.DynamicScriptEngineFactory;
+import org.hswebframework.web.BusinessException;
+import org.hswebframework.web.authorization.Authorization;
+import org.hswebframework.web.authorization.annotation.RequiresExpression;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.annotation.Annotation;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * TODO 完成注释
+ *
+ * @author zhouhao
+ */
+public class ExpressionAnnotationMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {
+    public ExpressionAnnotationMethodInterceptor() {
+        super(new ExpressionAnnotationHandler());
+    }
+
+    private static final Logger logger = LoggerFactory.getLogger(ExpressionAnnotationMethodInterceptor.class);
+
+    static class ExpressionAnnotationHandler extends AuthorizingAnnotationHandler {
+
+        public ExpressionAnnotationHandler() {
+            super(RequiresExpression.class);
+        }
+
+        @Override
+        public void assertAuthorized(Annotation a) throws AuthorizationException {
+            if (!(a instanceof RequiresExpression)) return;
+            MethodInterceptorHolder holder = MethodInterceptorHolder.current();
+            if (null == holder) {
+                return;
+            }
+            RequiresExpression expression = ((RequiresExpression) a);
+            DynamicScriptEngine engine = DynamicScriptEngineFactory.getEngine(expression.language());
+            if (null == engine) {
+                throw new AuthorizationException("{unknown_engine}:" + expression.language());
+            }
+            if (!engine.compiled(holder.getId())) {
+                try {
+                    engine.compile(holder.getId(), expression.value());
+                } catch (Exception e) {
+                    logger.error("express compile error", e);
+                    throw new BusinessException("{expression_error}");
+                }
+            }
+            Map<String, Object> var = new HashMap<>(holder.getArgs());
+            var.put("auth", getSubject().getSession().getAttribute(Authorization.class.getName()));
+            Object success = engine.execute(holder.getId(), var).get();
+            if (!(success instanceof Boolean) || !((Boolean) success)) {
+                throw new AuthorizationException();
+            }
+        }
+    }
+}

+ 78 - 0
hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/boost/MethodInterceptorHolder.java

@@ -0,0 +1,78 @@
+/*
+ * 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.hswebframework.web.ThreadLocalUtils;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+/**
+ * TODO 完成注释
+ *
+ * @author zhouhao
+ */
+public class MethodInterceptorHolder {
+
+    public static MethodInterceptorHolder current() {
+        return ThreadLocalUtils.get(MethodInterceptorHolder.class.getName());
+    }
+
+    public static MethodInterceptorHolder clear() {
+        return ThreadLocalUtils.getAndRemove(MethodInterceptorHolder.class.getName());
+    }
+
+    public static MethodInterceptorHolder setCurrent(MethodInterceptorHolder holder) {
+        return ThreadLocalUtils.put(MethodInterceptorHolder.class.getName(), holder);
+    }
+
+    private String id;
+
+    private Method method;
+
+    private Object target;
+
+    private Map<String, Object> args;
+
+    public void set() {
+        MethodInterceptorHolder.setCurrent(this);
+    }
+
+    public MethodInterceptorHolder(String id, Method method, Object target, Map<String, Object> args) {
+        this.id = id;
+        this.method = method;
+        this.target = target;
+        this.args = args;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public Method getMethod() {
+        return method;
+    }
+
+    public Object getTarget() {
+        return target;
+    }
+
+    public Map<String, Object> getArgs() {
+        return args;
+    }
+}

+ 41 - 0
hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/cache/SpringCacheManagerWrapper.java

@@ -0,0 +1,41 @@
+/*
+ * 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.cache;
+
+import org.apache.shiro.cache.AbstractCacheManager;
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.cache.CacheException;
+import org.springframework.cache.CacheManager;
+
+/**
+ * TODO 完成注释
+ *
+ * @author zhouhao
+ */
+public class SpringCacheManagerWrapper extends AbstractCacheManager {
+    private org.springframework.cache.CacheManager springCacheManager;
+
+    public SpringCacheManagerWrapper(CacheManager springCacheManager) {
+        this.springCacheManager = springCacheManager;
+    }
+
+    @Override
+    protected Cache createCache(String name) throws CacheException {
+        return new SpringCacheWrapper(springCacheManager.getCache(name));
+    }
+}

+ 76 - 0
hsweb-authorization/hsweb-authorization-shiro/src/main/java/org/hswebframework/web/authorization/shiro/cache/SpringCacheWrapper.java

@@ -0,0 +1,76 @@
+/*
+ * 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.cache;
+
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.cache.CacheException;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * TODO 完成注释
+ *
+ * @author zhouhao
+ */
+@SuppressWarnings("unchecked")
+public class SpringCacheWrapper<K, V> implements Cache<K, V> {
+    private org.springframework.cache.Cache springCache;
+
+    public SpringCacheWrapper(org.springframework.cache.Cache springCache) {
+        this.springCache = springCache;
+    }
+
+    @Override
+    public V get(K key) throws CacheException {
+        return (V) springCache.get(key);
+    }
+
+    @Override
+    public V put(K key, V value) throws CacheException {
+        springCache.put(key, value);
+        return value;
+    }
+
+    @Override
+    public V remove(K key) throws CacheException {
+        V old = get(key);
+        springCache.evict(key);
+        return old;
+    }
+
+    @Override
+    public void clear() throws CacheException {
+        springCache.clear();
+    }
+
+    @Override
+    public int size() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<K> keys() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Collection<V> values() {
+        throw new UnsupportedOperationException();
+    }
+}

+ 1 - 4
hsweb-authorization/hsweb-authorization-shiro/src/test/java/org/hswebframework/web/authorization/shiro/ShiroTests.java

@@ -25,7 +25,6 @@ import org.apache.shiro.mgt.DefaultSecurityManager;
 import org.apache.shiro.realm.SimpleAccountRealm;
 import org.apache.shiro.session.mgt.DefaultSessionManager;
 import org.apache.shiro.subject.Subject;
-import org.hswebframework.web.authorization.UserSubjectUtils;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -42,6 +41,7 @@ public class ShiroTests {
         securityManager.setAuthenticator(new ModularRealmAuthenticator());
         SimpleAccountRealm realm = new SimpleAccountRealm();
         realm.addAccount("admin", "admin", "admin");
+
         securityManager.setRealm(realm);
         securityManager.setSessionManager(sessionManager);
         SecurityUtils.setSecurityManager(securityManager);
@@ -53,10 +53,7 @@ public class ShiroTests {
         Assert.assertTrue(subject.isAuthenticated());
         Assert.assertTrue(subject.hasRole("admin"));
         Assert.assertFalse(subject.hasRole("test"));
-        new ShiroUserSubjectUtils().bind();
 
-        Assert.assertTrue(UserSubjectUtils.get().hasRole("admin"));
-        Assert.assertEquals(UserSubjectUtils.get().getUsername(), "admin");
         System.out.println();
     }
 }