• 若依-匿名注解@Anonymous解析


    1、实现绕过权限认证,可以直接访问某些接口。
    这些部分可以直接在Spring Security中的配置去写,也可以像这个主角这样给添加了注解的方法或类进行放行。
      原理:在spring security设置拦截前,获取到所有添加了该注解的请求,把这些请求添加到放开拦截的配置中。
    2、实现
    a)新增注解(注解中内容是可以空的)

    @Target({ElementType.TYPE,ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Anonymous {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    b)在spring security进行配置的时候,获取到添加了注解的类或方法

    之前使用注解的时候都是在切面中,也就是当程序执行到添加了注解时程序能运行到切面里的代码。现在要在spring初始化bean后获取到全部的请求信息,在spring的生命周期 afterPropertiesSet时 通过调用

      RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
      Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
    
    • 1
    • 2

    可以获取到。这个逻辑封装到了工具类 PermitAllUrlProperties中。

    @Configuration
    public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware {
        /**
         * 正则表达式 匹配path variable
         * 如: @GetMapping(value = "/configKey/{configKey}") 进行匹配后替换为/configKey/*
         *
         */
        private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
    
        /**
         * spring 上下文
         * 从中可以获取到各种bean
         */
        private ApplicationContext applicationContext;
        /**
         * 该集合中保存了全部标记过匿名注解的url请求
         */
        private List<String> urls = new ArrayList<>();
    
        public String ASTERISK = "*";
    
        @Override
        public void afterPropertiesSet()  {
            // 获取全部的handlerMappings
            RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
            Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
    
            map.keySet().forEach(info->{
                HandlerMethod handlerMethod = map.get(info);
                // 获取方法上的注解 替代path variable 为 *
                Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class);
                Optional.ofNullable(method).ifPresent(anonymous->info.getPatternsCondition().getPatterns()
                        .forEach(url->urls.add(RegExUtils.replaceAll(url,PATTERN,ASTERISK))));
    
                // 获取类上的注解
                Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class);
                Optional.ofNullable(controller).ifPresent(anonymous->info.getPatternsCondition().getPatterns()
                        .forEach(url->urls.add(RegExUtils.replaceAll(url,PATTERN,ASTERISK))));
    
            });
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    
        public List<String> getUrls() {
            return urls;
        }
    
        public void setUrls(List<String> urls) {
            this.urls = urls;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    c)配置放开拦截

    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        ...
        @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        // 注解标记允许匿名访问的url
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();
        permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());
        ... 其他配置
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3、 测试

    目前对于没有添加匿名注解的都会拦截不允许访问。

    4、总结

    公共的方法很多都是通过注解、切面进行实现的;结合spring的生命周期函数,实现公共逻辑的处理。很多时候是结合了servlet和过程和spring的能力进行处理的。

    代码中添加了很多spring security的配置,以及涉及到的一些工具类。framework.config.SecurityConfig是Spring Security的配置的核心,从这个类会把对security的扩展配置进去的。UserDetailsServiceImpl是重点类,实现认证过的关键类。spring security的配置和扩展很多,需要理解下原理去梳理下常见的配置内容,但是总之就是去配置和扩展框架。

  • 相关阅读:
    GAN的详细介绍及其应用(全面且完整)
    Spring aop的简化版本
    如何保证用户重试操作的幂等性
    为何TI的GPMC并口,更常被用于连接FPGA、ADC?我给出3个理由
    Spring5框架学习笔记(四)
    25G、50G、100G以太网介绍,网络工程师收藏!
    JAVA代码审计——SQL注入靶场审计01
    【Linux】vi命令使用详解(vim编辑器)
    MySQL进阶-索引生效和设计的原则总结
    一个技术混子参加《 2022 谷歌开发者大会》的一日游记
  • 原文地址:https://blog.csdn.net/weixin_44749255/article/details/133923974