SpringSecurity ,oAuth2.0 从入门到源码精通 之 (六)spring security 配置多条过滤器链

在前一篇文章中,我们介绍了 Spring Security 的启动流程和配置流程,在介绍 WebSecurity 时,我们提到可以创建多个 WebSecurityConfigurerAdapter 的子类实例,也就会创建多条过滤器链,今天我们就来简单了解一下如何配置多个过滤器链。

1 简单配置

配置方法很简单,我们直接上代码:

创建一个配置类,再在该类中创建几个 WebSecurityConfigurerAdapter 的子类,并给这些类加上 @Order 和 @Configuration 注解:

MultipleWebSecurityConfig.java:

@Configuration
public class MultipleWebSecurityConfig {
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    //用户信息
    @Autowired
    protected void authUserInfo(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("llk")
                .password(passwordEncoder().encode("1234"))
                .authorities("USER")
                .and()
                .withUser("zhangsan")
                .password(passwordEncoder().encode("123456"))
                .authorities("USER");
    }

    @Order(1)
    @Configuration
    class AdminSecurityConfig extends WebSecurityConfigurerAdapter{
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                    .antMatcher("/admin/**")
                    .csrf().disable()
                    .authorizeRequests()
                    .antMatchers("/admin/book/delete").hasAuthority("ADMIN")
                    .antMatchers("/admin/book/update").hasAnyAuthority("ADMIN")
                    .anyRequest().authenticated();
            ;
        }
    }

    @Order(2)
    @Configuration
    class CommonSecurityConfig extends WebSecurityConfigurerAdapter{

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                    .antMatcher("/common/**")
                    .csrf().disable()
                    .authorizeRequests()
                    .antMatchers("/common/book/get").hasAuthority("USER")
                    .anyRequest().authenticated();
            ;
        }
    }
}

需要给 http 指定一个 **antMatcher() 值 /admin 开头的请求将交给 AdminSecurityConfig 对应的过滤器链,以 /common 开头的请求将交给 CommonSecurityConfig 对应的过滤器链。

下面我们还是以书籍管理系统的接口来测试一下。

我们这里只是做一个简单的例子,普通用户具有 USER 权限,请求以 /common 开头;管理员用户具有 ADMIN 和 USER 权限,请求以 /admin 开头。

BookController.java:

@RestController
public class BookController {
    @RequestMapping("/common/book/get")
    public Book get(){
        Book book = new Book();
        book.setBookId("1");
        book.setBookName("《Thinking in Java》");
        book.setAuthor("Bruce Eckel");

        return book;
    }
    @RequestMapping("/admin/book/delete")
    public String delete(){
        //模拟删除书籍的代码
        System.out.println("删除书籍");
        return "删除成功";
    }

我们在浏览器输入访问书籍信息的 URL:http://localhost:8080/common/book/get ,然后回车,却发现没有显示我们的书籍信息,而是显示 403

在这里插入图片描述
出现这个的原因,是因为我们还没有登录,没有权限访问。

那么我们就去登录,照以前一样,输入 Spring Security 默认的登录界面地址:http://localhost:8080/login ,访问后我们发现报 404 错误了。

报 404 的原因:大家看一下在上一篇文章中介绍的一个图:
在这里插入图片描述
上图中清晰的展示了,当一个请求到 FilterChainProxy(DelegatingFilterProxy ) 时,Spring Security 会去判断当前请求应该由哪一条过滤器链来处理,由于我们前面的配置中只配置了处理以 /admin 和以 /common 开头的请求,所以当我们访问 /login 时就被 FilterChainProxy 抛弃了,因为没有与 /login 对应的过滤器链。

为解决这个问题,我们可以为每一个过滤器链都配置 formLogin() 相关的信息,具体配置我们这里不极少了,在第一篇文章中已经介绍过。

一般情况下,我们再配置一条过滤器链,拦截除了以 /admin 和 /common 以外的请求,具体的情况根据你的业务需求来定。

MultipleWebSecurityConfig.java 中添加如下配置:

	@Order(3)
    @Configuration
    class OtherSecurityConfig extends WebSecurityConfigurerAdapter{

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                    .csrf().disable()
                    .formLogin()
                    //表单登录相关
                    .permitAll()
                    .and()
                    .authorizeRequests()
                    .anyRequest().authenticated();
            ;
        }
    }

该配置是向 FilterChainProxy 中添加了一个拦截路径为根路径 / 的过滤器链,即该过滤器链可以拦截所有的请求。

到此为止,配置多个过滤器链的功能,就算完成,对于每一条过滤器链要应用哪些过滤器,通过 httpSecurity 参数去配置即可,这里我们就不做介绍了。

2 注意顺序

上面的代码中,我们在 WebSecurityConfigurerAdapter 的三个子类上都添加了一个 @Order 注解,在上一篇文章中,我们在介绍 WebSecurityConfiguration 时,创建 webSecurity 对象后,对 WebSecurityConfigurerAdapter 的子类进行了由小到大的排序,然后将这些 WebSecurityConfigurerAdapter 添加到了 webSecurityConfigurers 集合中,最后在 WebSecurityperformBuild() 方法中循环遍历 securityFilterChainBuilders 获取配置信息并创建过滤器链,创建好的过滤器链被添加到一个 ArrayList 类型的 securityFilterChains 集合中,再设置给了 filterChainProxy 对象。

当客户端发来一个请求时,执行到 FilterChainProxy 的 doFilterInternal() 方法,在该方法中将循环遍历 securityFilterChains 中的过滤器链然后与请求地址进行匹配,如果某个过滤器链匹配到了,就执行该过滤器链。

所以,我们就得注意 @Order 的顺序了,值越小优先级越高,不标注 @Order 注解的优先级最高谁的优先级越高,它对应的过滤器链就先被 FilterChainProxy 匹配,如果该过滤器链的匹配地址与请求地址一致则执行该过滤器链,否则继续检查下一个过滤器链是否匹配。

2.1 顺序验证

我们拿前面的 AdminSecurityConfig 和 OtherSecurityConfig 为例来说明配置之间的顺序的重要性。

在上面的代码中,AdminSecurityConfig 和 OtherSecurityConfig@Order 注解的值分别为 1 和 3,所以此时是先匹配 AdminSecurityConfig 对应的过滤器链。

此时如果我们直接在未登录的情况下访问 http://localhost:8080/admin/book/delete ,会告诉我们 403,没有权限访问,至于原因我们也知道了,已 /admin/ 开头的请求直接就被 AdminSecurityConfig 对应的过滤器链给执行了,然后在权限验证的时候,访问的用户没有 ADMIN 权限,所以就报 403 错误了,这个配置我们认为是安全的,因为我们拦住了没有登录的用户(没有 ADMIN 权限的登录用户也会被拦住)。

那么接下来,我们将 AdminSecurityConfig 和 OtherSecurityConfig 的 @Order 的值改为 3 和 1,这时 OtherSecurityConfig 对应的过滤器链会优先被匹配。由于 OtherSecurityConfig 的默认匹配路径是根路径,所以任何请求都会由它对应的过滤器链来处理,当我们在浏览器中输入 http://localhost:8080/admin/book/delete 地址后,我们用没有 ADMIN 权限的用户登录后,可以直接访问到删除书籍的接口,这显然不是我们想要的。至于原因大家应该也已经很清楚了,因为在我们的 OtherSecurityConfig 中并没有配置接口的相关权限信息(我们在 AdminSecurityConfig 中配置了,但是没有执行对应的过滤器链,所以没有拦截到没有权限的用户)。

所以,大家如果想对不同的路径使用不同的配置时,一定要小心 @Order 的顺序,要保证自己的配置能够被应用上。

本篇文章的内容只是上一篇文章的一个延续,帮助大家更加深入的理解 Spring Security 的配置流程。

3 示例代码

示例代码地址:https://github.com/coderllk/spring-security-oauth2-demos

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值