当前位置: 首页 > news >正文

基于注解方式实现Spring Security忽略拦截

文章目录

  • 1.Spring Security忽略拦截配置
  • 2.基于配置文件注入
    • 2.1.添加配置
    • 2.2.修改Spring Security配置类
    • 2.3. 测试
  • 3.基于注解的方式过滤接口
    • 3.1.添加注解
    • 3.2.获取所有使用了@IgnoreWebSecurity注解的接口访问路径
    • 3.3.测试

1.Spring Security忽略拦截配置

关于Spring Securite的使用可以参考我写的这篇博客: 【SpringBoot框架篇】16.security整合jwt实现对前后端分离的项目进行权限认证

像这种需要忽略某个接口需要在Spring Security配置类中在代码中写死,非常的不灵活。
在这里插入图片描述

2.基于配置文件注入

2.1.添加配置

一般像一些静态资源文件需要过滤掉安全认证,例如图片,.css,.js等静态资源文件,像这种在配置文件中指定比较方便。
application.yml配置

#不需要认证的接口地址
security:
  ignore:
   get:
     - /image/**
   post:

   all:

添加配置类注入配置的参数

@Configuration
@ConfigurationProperties(prefix = "security.ignore")
public class IgnoreSecurityPropetties {

    /**
     * 需要忽略的接口路径 不限制请求类型
     */
    private List<String> all;

    /**
     * 需要忽略的Get请求类型接口路径
     */
    private List<String> get;

    /**
     * 需要忽略的Post请求类型接口路径
     */
    private List<String> post;
    //省略 get,set方法

2.2.修改Spring Security配置类

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Resource
    private IgnoreSecurityPropetties ignoreSecurityPropetties;
    
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

        String[] all = new String[ignoreSecurityPropetties.getAll().size()];
        String[] get = new String[ignoreSecurityPropetties.getGet().size()];
        String[] post = new String[ignoreSecurityPropetties.getPost().size()];
        ignoreSecurityPropetties.getGet().toArray(get);
        ignoreSecurityPropetties.getPost().toArray(post);
        ignoreSecurityPropetties.getAll().toArray(all);

        if (all.length > 0) {
            authorizeRequest.antMatchers(all).permitAll();
        }
        if (get.length > 0) {
            authorizeRequest.antMatchers(HttpMethod.GET, get).permitAll();
        }
        if (post.length > 0) {
            authorizeRequest.antMatchers(HttpMethod.POST, post).permitAll();
        }
        // 其它接口都要认证
        authorizeRequest.anyRequest().authenticated();

    }
}    

2.3. 测试

@RestController
@RequestMapping("/test")
public class TestIgnoreController {

    @GetMapping("/image/{id}")
    public String image(@PathVariable String id) {
        return id;
    }
}   

在这里插入图片描述

如果从配置文件中删除了过滤的接口名称则访问接口会返回403
在这里插入图片描述

3.基于注解的方式过滤接口

3.1.添加注解

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreWebSecurity {

    /**
     * 忽略接口的名称,默认使用Controller访问路径加接口的的访问路径组件 
     * 使用场景匹配url穿参的动态匹配 例如: /user/{id},像这种需要配置注解值为 /user/*
     */
    String value() default "";

}

3.2.获取所有使用了@IgnoreWebSecurity注解的接口访问路径

  • 用到了2.2中的IgnoreSecurityPropetties类存放忽略的接口名称
  • 用到了2.3中的修改security配置类
@Configuration
public class InitIgnoreWebSecurityConfig implements ApplicationContextAware {

    @Autowired
    private IgnoreSecurityPropetties ignoreSecurityPropetties;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        Map<String, Object> beanMap = applicationContext.getBeansWithAnnotation(RestController.class);
        beanMap.forEach((k, v) -> {

            //Controllers配置的访问路径
            String baseUrl = "";
            Class<?> controllerClass = v.getClass();
            RequestMapping annotation = AnnotatedElementUtils.findMergedAnnotation(controllerClass, RequestMapping.class);

            //如果RequestMapping注解存在,使用RequestMapping里配置的路径名称
            if (annotation != null) {
                baseUrl = annotation.value().length > 0 ? annotation.value()[0] : "";
            }

            //判断访问路径前缀是否包含/
            if (!baseUrl.startsWith("/")) {
                baseUrl = "/" + baseUrl;
            }

            //获取所有声明的方法
            Method[] allMethods = controllerClass.getMethods();
            IgnoreWebSecurity ignoreWebSecurity;
            PostMapping postMapping;
            GetMapping getMapping;
            String methodType;

            for (Method method : allMethods) {
                methodType = "";
                //判断方法是否使用忽略权限认证注解
                ignoreWebSecurity = AnnotatedElementUtils.findMergedAnnotation(method, IgnoreWebSecurity.class);
                if (ignoreWebSecurity != null) {
                    String url = "";
                    //当注解没配置接口名称时候使用接口名称(Controller访问路径+接口访问路径)
                    //目前只适配了PostMapping和GetMapping注解,其它类型请自行扩展
                    postMapping = AnnotatedElementUtils.findMergedAnnotation(method, PostMapping.class);
                    if (postMapping != null) {
                        url = postMapping.value().length > 0 ? postMapping.value()[0] : "";
                        methodType = "post";
                    } else {
                        getMapping = AnnotatedElementUtils.findMergedAnnotation(method, GetMapping.class);
                        if (getMapping != null) {
                            url = getMapping.value().length > 0 ? getMapping.value()[0] : "";
                            methodType = "get";
                        }
                    }
                    //注解如果配置了接口路径则使用注解内的
                    if (StringUtils.hasText(ignoreWebSecurity.value())) {
                        url = ignoreWebSecurity.value();
                    }
                    if (url.trim().length() > 0) {
                        url = (baseUrl + "/" + url).replaceAll("/+", "/");
                    } else {
                        url = baseUrl;
                    }
                    if ("post".equals(methodType)) {
                        ignoreSecurityPropetties.getPost().add(url);
                    } else if ("get".equals(methodType)) {
                        ignoreSecurityPropetties.getGet().add(url);
                    }
                }
            }
        });
        System.out.println("需要忽略的get请求类型接口路径如下" );
        for(String get: ignoreSecurityPropetties.getGet()){
            System.out.println(get);
        }
        System.out.println("需要忽略的post请求类型接口路径如下");
        for(String post: ignoreSecurityPropetties.getPost()){
            System.out.println(post);
        }
    }
    
}

启动后会输出
在这里插入图片描述

忽略的接口访问路径规则以下文3.3的测试接口为例,
String baseUrl=@RestController控制器的访问路径(/test)
优先级1: String url=baseUrl+IgnoreWebSecurity(注解内值) =/test/css/*
优先级2: String url=baseUrl+接口访问路径(/login) =/test/login

3.3.测试

在需要忽略认证的接口上面添加@IgnoreWebSecurity注解

@RestController
@RequestMapping("/test")
public class TestIgnoreController {

    @IgnoreWebSecurity("/css/*")
    @GetMapping("/css/{id}")
    public String css(@PathVariable String id) {
        return id;
    }

    @IgnoreWebSecurity
    @GetMapping("/login")
    public String login() {
        return "登录成功";
    }
}

测试用注解修饰的接口路径,可以正常访问,由此可看配置是正常。
在这里插入图片描述

相关文章:

  • Leetcode 1792. 最大平均通过率 题解
  • k8s之多方面多维度的资源隔离和限制(namespace,LimitRange,ResourceQuota)
  • Himall商城更新插件列表\获取插件程序集文件\ 深复制IPlugin
  • 【Web前端HTML5CSS3】09、高度塌陷与 BFC
  • Java中toString方法的推荐实现方式
  • 构建系列之新一代利器Esbuild(上)
  • MIUI10国际版系统自定义字体设置办法
  • webpack 构建脚手架
  • 2022吴恩达机器学习课程——第三课(非监督学习)
  • PGP邮件加密软件的使用
  • LabVIEW如何减少下一代测试系统中的硬件过时 1
  • 全国职业院校技能大赛中职组网络安全竞赛试题 —文件包含漏洞与文件上传漏洞 (笔记文档)
  • java学习day64(乐友商城)Elasticsearch
  • Fabric.js 保存自定义属性
  • 【软件测试】测试人的懊恼,你要揭开的秘密复现bug......
  • 嵌入式C语言面向对象编程 --- 封装
  • 第十九章 webpack5项目搭建Vue-Cli(合并配置)
  • 设计好接口的36个锦囊
  • 我以为自己MySQL够牛逼了,直到看到了Alibaba的面试题
  • 解决vue代码不规范而出现的问题:Eslint修复