咱們先來看一個簡單的配置: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 篇,閱讀前面文章有助於更好的理解本文:數據庫
在 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
若是咱們使用了 Java 配置,這些 XML 配置都有對應的寫法,例如 .anyRequest().authenticated()
就是配置攔截規則的,.formLogin()
是配置表單登陸細節的。框架
僅僅從語義層面來理解,and 有點相似於 XML 中的結束標籤,每當 and 出現,當前的配置項就結束了,能夠開啓下一個配置了。
那麼從代碼層面上,這個要如何理解呢?
小夥伴們知道,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 的配置爲例,有兩個方法:
@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) 方法中的配置過程。
經過前面的講解,不知道小夥伴們有沒有看懂呢?我再給你們總結下。
Spring Security 的功能主要是經過各類各樣的過濾器來實現的,各類各樣的過濾器都由對應的 xxxConfigurer 來進行配置,咱們在 configure(HttpSecurity http) 中所作的配置其實就是在配置 xxxConfigurer,也是在間接的配置過濾器,每個 and 方法會將咱們帶回到 HttpSecurity 實例中,從而開啓新一輪的配置。
大體就是這樣!文章案例下載地址:https://github.com/lenve/spring-security-samples
小夥伴們若是以爲有收穫,記得點個在看鼓勵下鬆哥哦~