如何分析Spring Security中过滤器链的配置问题

发布时间:2021-12-02 15:57:14 作者:柒染
来源:亿速云 阅读:351

如何分析Spring Security中过滤器链的配置问题,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

首先这个问题本身是有点问题的,因为 http.authorizeRequests() 并非总是第一个,虽然大部分情况下,我们看到的是第一个,但是也有很多情况 http.authorizeRequests() 不是首先出现。要搞明白这个问题,我们就要搞清楚 http.authorizeRequests() 到底是啥意思!

这就涉及到 Spring Security 中过滤器链的配置问题

 

1.从过滤器开始

即使大家没有仔细研究过 Spring Security 中认证、授权功能的实现机制,大概也都多多少少听说过 Spring Security 这些功能是通过过滤器来实现的。

是的,没错!Spring Security 中一共提供了 32 个过滤器,其中默认使用的有 15 个,这些过滤器松哥在以后的文章中再和大家细说,今天我们就先来看看过滤器的配置问题。

在一个 Web 项目中,请求流程大概如下图所示:

如何分析Spring Security中过滤器链的配置问题  

请求从客户端发起(例如浏览器),然后穿过层层 Filter,最终来到 Servlet 上,被 Servlet 所处理。

那有小伙伴要问了,Spring Security 中默认的 15 个过滤器就是这样嵌套在 Client 和 Servlet 之间吗?

不是的!

上图中的 Filter 我们可以称之为 Web Filter,Spring Security 中的 Filter 我们可以称之为 Security Filter,它们之间的关系如下图:

如何分析Spring Security中过滤器链的配置问题  

可以看到,Spring Security Filter 并不是直接嵌入到 Web Filter 中的,而是通过 FilterChainProxy 来统一管理 Spring Security Filter,FilterChainProxy 本身则通过 Spring 提供的 DelegatingFilterProxy 代理过滤器嵌入到 Web Filter 之中。

❝  

DelegatingFilterProxy 很多小伙伴应该比较熟悉,在 Spring 中手工整合 Spring Session、Shiro 等工具时都离不开它,现在用了 Spring Boot,很多事情 Spring Boot 帮我们做了,所以有时候会感觉 DelegatingFilterProxy 的存在感有所降低,实际上它一直都在。

 

2.多个过滤器链

上面和大家介绍的是单个过滤器链,实际上,在 Spring Security 中,可能存在多个过滤器链。

在松哥前面讲 OAuth3 系列的时候,有涉及到多个过滤器链,但是一直没有拎出来单独讲过,今天就来和大家分享一下。

有人会问,下面这种配置是不是就是多个过滤器链?

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("admin")
            .antMatchers("/user/**").hasRole("user")
            .anyRequest().authenticated()
            ...
            .csrf().disable();
}
 

这样的配置相信大家都见过,但是这并不是多个过滤器链,这是一个过滤器链。因为不管是 /admin/** 还是 /user/** ,走过的过滤器都是一样的,只是不同的路径判断条件不一样而已。

如果系统存在多个过滤器链,多个过滤器链会在 FilterChainProxy 中进行划分,如下图:

如何分析Spring Security中过滤器链的配置问题  

可以看到,当请求到达 FilterChainProxy 之后,FilterChainProxy 会根据请求的路径,将请求转发到不同的 Spring Security Filters 上面去,不同的 Spring Security Filters 对应了不同的过滤器,也就是不同的请求将经过不同的过滤器。

正常情况下,我们配置的都是一个过滤器链,多个过滤器链怎么配置呢?松哥给大家一个举一个简单的例子:

@Configuration
public class SecurityConfig {
    @Bean
    protected UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("javaboy").password("{bcrypt}$2a$10$Sb1gAUH4wwazfNiqflKZve4Ubh.spJcxgHG8Cp29DeGya5zsHENqi").roles("admin", "aaa", "bbb").build());
        manager.createUser(User.withUsername("sang").password("{noop}123").roles("admin").build());
        manager.createUser(User.withUsername("江南一点雨").password("{MD5}{Wucj/L8wMTMzFi3oBKWsETNeXbMFaHZW9vCK9mahMHc=}4d43db282b36d7f0421498fdc693f2a2").roles("user", "aaa", "bbb").build());
        return manager;
    }

    @Configuration
    @Order(1)
    static class DefaultWebSecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/foo/**")
                    .authorizeRequests()
                    .anyRequest().hasRole("admin")
                    .and()
                    .csrf().disable();
        }
    }

    @Configuration
    @Order(2)
    static class DefaultWebSecurityConfig2 extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/bar/**")
                    .authorizeRequests()
                    .anyRequest().hasRole("user")
                    .and()
                    .formLogin()
                    .permitAll()
                    .and()
                    .csrf().disable();
        }
    }
}
 
  1. 首先,SecurityConfig 不再需要继承自 WebSecurityConfigurerAdapter 了,只是作为一个普通的配置类,加上 @Configuration 注解即可。
  2. 提供 UserDetailsService 实例,相当于是我们的数据源。
  3. 创建静态内部类继承 WebSecurityConfigurerAdapter 类,同时用 @Configuration 注解标记静态内部类是一个配置类,配置类里边的代码就和之前的一样了,无需赘述。
  4. 每一个静态内部类相当于就是一个过滤器链的配置。
  5. 注意在静态内部类里边,我没有使用     http.authorizeRequests() 开始,     http.authorizeRequests() 配置表示该过滤器链过滤的路径是     /**。在静态内部类里边,我是用了     http.antMatcher("/bar/**") 开启配置,表示将当前过滤器链的拦截范围限定在     /bar/**
  6. 当存在多个过滤器链的时候,必然会有一个优先级的问题,所以每一个过滤器链的配置类上通过 @Order(2) 注解来标记优先级。

从上面这段代码中大家可以看到,configure(HttpSecurity http) 方法似乎就是在配置过滤器链?是的没错!我们在该方法中的配置,都是在添加/移除/修改 Spring Security 默认提供的过滤器,所以该方法就是在配置 Spring Security 中的过滤器链,至于是怎么配置的,松哥以后抽时间再来和大家细说。

 

3.回到问题

最后,我们在回到一开始小伙伴提的问题。

首先,http.authorizeRequests() 配置并非总在第一行出现,如果只有一个过滤器链,他总是在第一行出现,表示该过滤器链的拦截规则是 /**请求只有先被过滤器链拦截下来,接下来才会进入到不同的 Security Filters 中进行处理),如果存在多个过滤器链,就不一定了。

仅仅从字面意思来理解,authorizeRequests() 方法的返回值是 ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry,ExpressionUrlAuthorizationConfigurer 可以为多组不同的 RequestMatcher 配置不同的权限规则,就是大家看到的 .antMatchers("/admin/**").hasRole("admin").antMatchers("/user/**").hasRole("user")

看完上述内容,你们掌握如何分析Spring Security中过滤器链的配置问题的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!

推荐阅读:
  1. Spring Security常用过滤器实例解析
  2. 如何使用Spring Security手动验证用户的方法示例

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring security

上一篇:网站优化策略有哪些

下一篇:tk.Mybatis插入数据获取Id怎么实现

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》