• 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;
        }
    

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

  • 相关阅读:
    【Android】: 部分注意事项
    【Java】:多线程下载
    【操作系统】:Main features of the X86-64
    「数据结构」:模拟指针(simulated pointer)
    「JAVA」:Berkeley DB的JAVA连接
    「python」: arp脚本的两种方法
    「数据结构」: 间接寻址
    「操作系统」: Conditional Move Instructions(trap)
    「操作系统」:The most useful condition codes
    quartz定时任务时间设置
  • 原文地址:https://www.cnblogs.com/exmyth/p/15400955.html
Copyright © 2020-2023  润新知