zoukankan      html  css  js  c++  java
  • Shiro配置跳过权限验证

    需求

    因为在开发环境,测试环境,有时候需要跳过shiro的权限验证.所以想写个简单的配置跳过shiro的权限验证.
    跳过权限验证的原理就是重写**@RequiresPermissions**的实现,然后在配置文件中写一个开关,最后通过Aop注入进去就大功告成.

    @RequiresPermissions 处理类

    在 org.apache.shiro.authz.aop.PermissionAnnotationHandler 中处理这个注解,这就是我们要
    覆写的类.我准备将它替换成log日志.

    /**
     * 检查是否有@{@link org.apache.shiro.authz.annotation。注释是
     *声明,如果是,执行权限检查,看是否允许调用Subject继续
     *访问。
     *
     * @since 0.9.0
     */
    public class PermissionAnnotationHandler extends AuthorizingAnnotationHandler {
      
       /**
         *确保调用Subject具有注释指定的权限,如果没有,则抛出
         * AuthorizingException表示拒绝访问。
         * 
         */
        public void assertAuthorized(Annotation a) throws AuthorizationException {
            if (!(a instanceof RequiresPermissions)) return;
    
            RequiresPermissions rpAnnotation = (RequiresPermissions) a;
            //获取注解的值
            String[] perms = getAnnotationValue(a);
            //获取主体
            Subject subject = getSubject();
    
    		//如果只有一个需要权限
            if (perms.length == 1) {
                subject.checkPermission(perms[0]);
                return;
            }
            //与的处理
            if (Logical.AND.equals(rpAnnotation.logical())) {
                getSubject().checkPermissions(perms);
                return;
            }
            //或的处理
            if (Logical.OR.equals(rpAnnotation.logical())) {
                // Avoid processing exceptions unnecessarily - "delay" throwing the exception by calling hasRole first
                boolean hasAtLeastOnePermission = false;
                for (String permission : perms) if (getSubject().isPermitted(permission)) hasAtLeastOnePermission = true;
                // Cause the exception if none of the role match, note that the exception message will be a bit misleading
                if (!hasAtLeastOnePermission) getSubject().checkPermission(perms[0]);
                
            }
        }
    }
    
    

    通过 AopAllianceAnnotationsAuthorizingMethodInterceptor 加入拦截处理,通过Shiro starter 的 Conguration配置到将AuthorizationAttributeSourceAdvisor注入到 Spring Bean中.AuthorizationAttributeSourceAdvisor 实现了 StaticMethodMatcherPointcutAdvisor

    破解

    既然找到了实现的方法,那么注入一个自己实现类就可以跳过shiro的权限了.
    但是为了只在测试和开发环境破解,需要使用配置来实现

    1.配置跳过shiro开关

    首先在spring的配置中加入 spring.profiles.active ,同时配置 xfs.shiro.skipShiro为true.
    破解时根据当前运行环境和skipShiro来判断是否要跳过shiro

    spring:
      # 环境 dev|test|prod
      profiles:
        active: dev
      application:
        name: system
    xfs:
      shiro:
        skipShiro: true #危险配置,跳过shiro权限控制,用于开发和测试环境调试,慎用
    
    2.重写自己的@RequiresPermissions处理方法

    在日志上打log,防止严重的生产问题

    package cn.lanhi.auth.starter.interceptor;
    
    import com.alibaba.fastjson.JSON;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.shiro.authz.AuthorizationException;
    import org.apache.shiro.authz.annotation.RequiresPermissions;
    import org.apache.shiro.authz.aop.PermissionAnnotationHandler;
    
    import java.lang.annotation.Annotation;
    
    /**
     *
    
     *
     * @author : snx cn.shennaixin@gmail.net
     * @date : 2020-06-16 11:39
     */
    @Slf4j
    public class ShiroPermissionHandler extends PermissionAnnotationHandler {
         
    
    
        public ShiroPermissionHandler() {
         
            super();
            log.warn("使用了自定义的PermissionHandler,如果是生产环境,使用这个类将会导致权限控制模块失效");
        }
    
        /**
         * 重写权限认证方法,仅仅打印log,不做拦截处理
         *
         * @param a 注解
         * @throws AuthorizationException 一个不可能抛出的异常
         */
        @Override
        public void assertAuthorized(Annotation a) throws AuthorizationException {
         
            if (!(a instanceof RequiresPermissions)) return;
            //如果是数组,打印效果不好,使用json序列化
            log.warn("警告!!   跳过了权限:{}", JSON.toJSONString(getAnnotationValue(a)));
        }
    }
    
    
    3.设置注解处理器

    在 AnnotationsAuthorizingMethodInterceptor 这个抽象类的实现类中,添加了对注解的拦截器

    
    package org.apache.shiro.spring.security.interceptor;
    
    public class AopAllianceAnnotationsAuthorizingMethodInterceptor
            extends AnnotationsAuthorizingMethodInterceptor implements MethodInterceptor {
         
    	//Shiro拦截器
        public AopAllianceAnnotationsAuthorizingMethodInterceptor() {
         
            List<AuthorizingAnnotationMethodInterceptor> interceptors =
                    new ArrayList<AuthorizingAnnotationMethodInterceptor>(5);
            AnnotationResolver resolver = new SpringAnnotationResolver();
            interceptors.add(new RoleAnnotationMethodInterceptor(resolver));
            //注入了我们要破解的权限控制拦截器,
            interceptors.add(new PermissionAnnotationMethodInterceptor(resolver));
            interceptors.add(new AuthenticatedAnnotationMethodInterceptor(resolver));
            interceptors.add(new UserAnnotationMethodInterceptor(resolver));
            interceptors.add(new GuestAnnotationMethodInterceptor(resolver));
    
            setMethodInterceptors(interceptors);
        	}
        	........
      }
    

    那么破解一下,自己继承一下AopAllianceAnnotationsAuthorizingMethodInterceptor,然后获取自身属性,修改值

    package cn.lanhi.auth.starter.shiro;
    
    import com.xfs.auth.starter.interceptor.ShiroPermissionHandler;
    import org.apache.shiro.authz.aop.AuthorizingAnnotationMethodInterceptor;
    import org.apache.shiro.authz.aop.PermissionAnnotationMethodInterceptor;
    import org.apache.shiro.spring.security.interceptor.AopAllianceAnnotationsAuthorizingMethodInterceptor;
    
    import java.util.List;
    import java.util.stream.Collectors;
    
    /**
     *

    shiro 权限重定义

    
     *
     * @author : snx cn.shennaixin@gmail.net
     * @date : 2020-06-16 11:34
     */
    public class ShiroMethodInterceptor extends AopAllianceAnnotationsAuthorizingMethodInterceptor {
         
        public ShiroMethodInterceptor() {
         
            super();
        }
    
        /**
         * 跳过shiro RequirePremissions 注解验证
         */
        public ShiroMethodInterceptor skipPremissionHandler() {
         
            List<AuthorizingAnnotationMethodInterceptor> interceptors = this.getMethodInterceptors().stream()
                    .filter(authorizingAnnotationMethodInterceptor ->
                            !(authorizingAnnotationMethodInterceptor instanceof PermissionAnnotationMethodInterceptor))
                    .collect(Collectors.toList());
            PermissionAnnotationMethodInterceptor interceptor = new PermissionAnnotationMethodInterceptor();
            //设置成自己的注解处理器!
            interceptor.setHandler(new ShiroPermissionHandler());
            interceptors.add(interceptor);
            setMethodInterceptors(interceptors);
            return this;
        }
    }
    
    
    4.重写shiroAop
    package org.apache.shiro.spring.config;
    /**
     * shiro AOP 
     * @since 1.4.0
     */
    @Configuration
    public class ShiroAnnotationProcessorConfiguration extends AbstractShiroAnnotationProcessorConfiguration{
         
    
        @Bean
        @DependsOn("lifecycleBeanPostProcessor")
        protected DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
         
            return super.defaultAdvisorAutoProxyCreator();
        }
    
        @Bean
        protected AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
         
            return super.authorizationAttributeSourceAdvisor(securityManager);
        }
    
    }
    
       --------------------
       --------------------
       --------------------
      这个 AuthorizationAttributeSourceAdvisor 提供了AOP的拦截器实现.接下来我们要覆盖他,
     /**
         * Create a new AuthorizationAttributeSourceAdvisor.
         */
        public AuthorizationAttributeSourceAdvisor() {
         
            setAdvice(new AopAllianceAnnotationsAuthorizingMethodInterceptor());
        }
       --------------------
       --------------------
       --------------------
    
    
    5.覆盖Shiro Bean

    判断了一下环境,跳过Shiro 权限验证,仅在测试和开发环境生效,且需要开启配置
    注意bean要设置成@primary

     /**
         * 跳过Shiro 权限验证,仅在测试和开发环境生效
         *
         * @param securityManager
         * @return
         */
        @Bean("authorizationAttributeSourceAdvisor")
        @Primary
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
                SecurityManager securityManager,
                Environment environment,
                @Value("${xfs.shiro.skipShiro:false}") boolean skipShiro) {
            //获取当前运行环境
            String profile = environment.getRequiredProperty("spring.profiles.active");
            //创建要生成的Bean
            AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager);
            //判断是否可以跳过shiro
            if (skipShiro && ("dev".equals(profile) || "test".equals(profile))) {
            	//运行跳过shiro权限验证方法
                advisor.setAdvice(new ShiroMethodInterceptor().skipPremissionHandler());
            }
            return advisor;
        }
    

    到此为止,就大功告成啦.

  • 相关阅读:
    leetcode 155. Min Stack 、232. Implement Queue using Stacks 、225. Implement Stack using Queues
    leetcode 557. Reverse Words in a String III 、151. Reverse Words in a String
    leetcode 153. Find Minimum in Rotated Sorted Array 、154. Find Minimum in Rotated Sorted Array II 、33. Search in Rotated Sorted Array 、81. Search in Rotated Sorted Array II 、704. Binary Search
    leetcode 344. Reverse String 、541. Reverse String II 、796. Rotate String
    leetcode 162. Find Peak Element
    leetcode 88. Merge Sorted Array
    leetcode 74. Search a 2D Matrix 、240. Search a 2D Matrix II
    Android的API版本和名称对应关系
    spring 定时任务执行两次解决办法
    解析字符串为泛型的方法
  • 原文地址:https://www.cnblogs.com/exmyth/p/15400955.html
Copyright © 2011-2022 走看看