Spring Security 配置中的 and 到底该怎么理解?

咱们先来看一个简单的配置:java

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginProcessingUrl("/doLogin")
            .permitAll()
            .and()
            .logout()
            .logoutUrl("/logout")
            .permitAll()
            .and()
            .csrf().disable();
}

这样的配置在 Spring Security 中很常见,经过 and 方法,能够将全部的配置链接在一块儿,一条线下来,全部的东西都配置好了。git

可是有小伙伴对这里的 and 表示很迷,不知道何时 and 方法该出场,何时 and 不应出场!github

因此今天松哥就花点时间来和你们聊一下这里的 and 方法,但愿你们看完完整后,可以明白 and 到底怎么玩!spring

本文是 Spring Security 系列第 33 篇,阅读前面文章有助于更好的理解本文:数据库

  1. 挖一个大坑,Spring Security 开搞!
  2. 松哥手把手带你入门 Spring Security,别再问密码怎么解密了
  3. 手把手教你定制 Spring Security 中的表单登陆
  4. Spring Security 作先后端分离,咱就别作页面跳转了!通通 JSON 交互
  5. Spring Security 中的受权操做原来这么简单
  6. Spring Security 如何将用户数据存入数据库?
  7. Spring Security+Spring Data Jpa 强强联手,安全管理只有更简单!
  8. Spring Boot + Spring Security 实现自动登陆功能
  9. Spring Boot 自动登陆,安全风险要怎么控制?
  10. 在微服务项目中,Spring Security 比 Shiro 强在哪?
  11. SpringSecurity 自定义认证逻辑的两种方式(高级玩法)
  12. Spring Security 中如何快速查看登陆用户 IP 地址等信息?
  13. Spring Security 自动踢掉前一个登陆用户,一个配置搞定!
  14. Spring Boot + Vue 先后端分离项目,如何踢掉已登陆用户?
  15. Spring Security 自带防火墙!你都不知道本身的系统有多安全!
  16. 什么是会话固定攻击?Spring Boot 中要如何防护会话固定攻击?
  17. 集群化部署,Spring Security 要如何处理 session 共享?
  18. 松哥手把手教你在 SpringBoot 中防护 CSRF 攻击!so easy!
  19. 要学就学透彻!Spring Security 中 CSRF 防护源码解析
  20. Spring Boot 中密码加密的两种姿式!
  21. Spring Security 要怎么学?为何必定要成体系的学习?
  22. Spring Security 两种资源放行策略,千万别用错了!
  23. 松哥手把手教你入门 Spring Boot + CAS 单点登陆
  24. Spring Boot 实现单点登陆的第三种方案!
  25. Spring Boot+CAS 单点登陆,如何对接数据库?
  26. Spring Boot+CAS 默认登陆页面太丑了,怎么办?
  27. 用 Swagger 测试接口,怎么在请求头中携带 Token?
  28. Spring Boot 中三种跨域场景总结
  29. Spring Boot 中如何实现 HTTP 认证?
  30. Spring Security 中的四种权限控制方式
  31. Spring Security 多种加密方案共存,老破旧系统整合利器!
  32. 神奇!本身 new 出来的对象同样也能够被 Spring 容器管理!

1.原始配置

在 Spring Boot 出现以前,咱们使用 Spring Security ,都是经过 XML 文件来配置 Spring Security 的,即便如今你们在网上搜索 Spring Security 的文章,仍是可以找到不少 XML 配置的。后端

可是小伙伴们明白,不管是 XML 配置仍是 Java 配置,只是在用不一样的方式描述同一件事情,从这里角度来看,咱们如今所使用的 Java 配置,和之前使用的 XML 配置,应该有某种殊途同归之妙。跨域

可能有小伙伴没见过 XML 配置的 Spring Security,我在这里给你们简单举几个例子:安全

<http>
    <intercept-url pattern="/login" access="permitAll" />
    <form-login login-page="/login" />
    <http-basic />
</http>

这段 XML 你们稍微瞅一眼大概就能明白其中的含义:session

  1. intercept-url 至关于配置拦截规则
  2. form-login 是配置表单登陆
  3. http-basic 是配置 HttpBasic 认证

若是咱们使用了 Java 配置,这些 XML 配置都有对应的写法,例如 .anyRequest().authenticated() 就是配置拦截规则的,.formLogin() 是配置表单登陆细节的。框架

仅仅从语义层面来理解,and 有点相似于 XML 中的结束标签,每当 and 出现,当前的配置项就结束了,能够开启下一个配置了。

那么从代码层面上,这个要如何理解呢?

2.代码层面的理解

小伙伴们知道,Spring Security 中的功能是由一系列的过滤器来实现的,默认的过滤器一共有 15 个,这 15 个过滤器松哥之后会和你们挨个介绍。

每个过滤器都有一个对应的 configurer 来对其进行配置,例如咱们常见的 UsernamePasswordAuthenticationFilter 过滤器就是经过 AbstractAuthenticationFilterConfigurer 来进行配置的。

这些 configure 都有一个共同的父类,那就是 SecurityConfigurer,给你们大体看一下 SecurityConfigurer 的继承关系图:

能够看到,它的实现类仍是蛮多的。

SecurityConfigurer 的源码很简单:

public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {
    void init(B builder) throws Exception;
    void configure(B builder) throws Exception;
}

就两个方法,第一个 init 用来作初始化操做,第二个 configure 用来作具体的配置。

在 Spring Security 框架初始化的时候,会把全部的这些 xxxConfigurer 收集起来,而后再统一调用每个 xxxConfigurer 里边的 init 和 configure 方法(松哥在之后的文章中会和你们详细讨论这个过程),调用完成后,Spring Security 默认的过滤器链就造成了。

这就是咱们所说的 xxxConfigurer 的做用!

在文章一开始,松哥列出来的示例代码中,HttpSecurity 中其实就是在配置各类各样的 xxxConfigurer。

SecurityConfigurer 有一个重要的实现类就是 SecurityConfigurerAdapter,默认的 15 个过滤器的 Configurer 类都是继承自它!而在 SecurityConfigurerAdapter 中就多出来一个方法:

public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
        implements SecurityConfigurer<O, B> {

    public void init(B builder) throws Exception {
    }

    public void configure(B builder) throws Exception {
    }
    public B and() {
        return getBuilder();
    }

}

没错,就是你们所熟知的 and 方法。and 方法的返回值是一个 SecurityBuilder 的子类,其实就是 HttpSecurity,也就是 and 方法老是让咱们回到 HttpSecurity,从而开启新一轮的 xxxConfigurer 配置。

咱们再来瞅一眼 HttpSecurity 中到底都有啥方法(方法比较多,我这里仅列举一部分):

能够看到,每个类型的配置,都有一个对应的返回 Configure 的方法,例如 OpenIDLoginConfigurer、HeadersConfigurer、CorsConfigurer 等等,你们注意,每个 configure 方法都有一个 HttpSecurity 做为泛型,这实际上就指定了 and 方法的返回类型。

我再举个例子,你们可能更清楚一些,以 HttpSecurity 中 RememberME 的配置为例,有两个方法:

  • RememberMeConfigurer<HttpSecurity> rememberMe()
  • HttpSecurity rememberMe(Customizer<RememberMeConfigurer<HttpSecurity>> rememberMeCustomizer)
  1. 第一个 rememberMe 方法没有参数,可是返回值是一个 RememberMeConfigurer,咱们能够在这个 RememberMeConfigurer 上继续配置 RememberME 相关的其余属性,配置完成后,经过 and 方法从新回到 HttpSecurity 对象,松哥前面文章基本上都是采用这种方式配置的,这里我就不重复举例子了。
  2. 第二个 rememberMe 方法有参数,参数是一个 Customizer ,可是带着一个 RememberMeConfigurer 泛型。其实 Customizer 就是一个接口,咱们能够经过匿名内部类的方式来实现该接口,这个接口中就一个实例方法,并且该方法的参数仍是你传入的泛型,即 RememberMeConfigurer,其实也就是咱们换了个地方去配置 RememberMeConfigurer 了,配置完成后,这个方法会直接返回 HttpSecurity,此时就再也不须要 and 方法了。配置示例以下(注意配置完成后不须要 and 方法就能继续后面的配置了):
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("admin")
            .antMatchers("/user/**").hasRole("user")
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .permitAll()
            .and()
            .rememberMe(new Customizer<RememberMeConfigurer<HttpSecurity>>() {
                @Override
                public void customize(RememberMeConfigurer<HttpSecurity> httpSecurityRememberMeConfigurer) {
                    httpSecurityRememberMeConfigurer.key("123");
                }
            })
            .csrf().disable();
}

这就是咱们在 configure(HttpSecurity http) 方法中的配置过程。

3.小结

经过前面的讲解,不知道小伙伴们有没有看懂呢?我再给你们总结下。

Spring Security 的功能主要是经过各类各样的过滤器来实现的,各类各样的过滤器都由对应的 xxxConfigurer 来进行配置,咱们在 configure(HttpSecurity http) 中所作的配置其实就是在配置 xxxConfigurer,也是在间接的配置过滤器,每个 and 方法会将咱们带回到 HttpSecurity 实例中,从而开启新一轮的配置。

大体就是这样!文章案例下载地址:https://github.com/lenve/spring-security-samples

小伙伴们若是以为有收获,记得点个在看鼓励下松哥哦~

相关文章
相关标签/搜索