## 核心配置解讀
本篇文章對上一次的配置做一個分析.
### 3.1 功能介紹
這是Spring Security入門指南中的配置項:
~~~
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("admin").roles("USER");
}
}
~~~
當配置了上述的javaconfig之后,我們的應用便具備了如下的功能:
* 除了“/”,”/home”(首頁),”/login”(登錄),”/logout”(注銷),之外,其他路徑都需要認證。
* 指定“/login”該路徑為登錄頁面,當未認證的用戶嘗試訪問任何受保護的資源時,都會跳轉到“/login”。
* 默認指定“/logout”為注銷頁面
* 配置一個內存中的用戶認證器,使用admin/admin作為用戶名和密碼,具有USER角色
* 防止CSRF攻擊
* Session Fixation protection(可以參考我之前講解Spring Session的文章,防止別人篡改sessionId)
* Security Header(添加一系列和Header相關的控制)
HTTP Strict Transport Security for secure requests
集成X-Content-Type-Options
緩存控制
集成X-XSS-Protection.aspx)
X-Frame-Options integration to help prevent Clickjacking(iframe被默認禁止使用)
* 為Servlet API集成了如下的幾個方法
HttpServletRequest#getRemoteUser())
HttpServletRequest.html#getUserPrincipal())
HttpServletRequest.html#isUserInRole(java.lang.String))
HttpServletRequest.html#login(java.lang.String, java.lang.String))
HttpServletRequest.html#logout())
### 3.2 @EnableWebSecurity
我們自己定義的配置類WebSecurityConfig加上了@EnableWebSecurity注解,同時繼承了WebSecurityConfigurerAdapter。你可能會在想誰的作用大一點,毫無疑問@EnableWebSecurity起到決定性的配置作用,它其實是個組合注解。
~~~
@Import({ WebSecurityConfiguration.class, // <2>
SpringWebMvcImportSelector.class }) // <1>
@EnableGlobalAuthentication // <3>
@Configuration
public @interface EnableWebSecurity {
boolean debug() default false;
}
~~~
@Import是springboot提供的用于引入外部的配置的注解,可以理解為:@EnableWebSecurity注解激活了@Import注解中包含的配置類。
<1> SpringWebMvcImportSelector的作用是判斷當前的環境是否包含springmvc,因為spring security可以在非spring環境下使用,為了避免DispatcherServlet的重復配置,所以使用了這個注解來區分。
<2> WebSecurityConfiguration顧名思義,是用來配置web安全的,下面的小節會詳細介紹。
<3> @EnableGlobalAuthentication注解的源碼如下:
~~~
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {
}
~~~
注意點同樣在@Import之中,它實際上激活了AuthenticationConfiguration這樣的一個配置類,用來配置認證相關的核心類。
也就是說:@EnableWebSecurity完成的工作便是加載了WebSecurityConfiguration,AuthenticationConfiguration這兩個核心配置類,也就此將spring security的職責劃分為了配置安全信息,配置認證信息兩部分。
#### WebSecurityConfiguration
在這個配置類中,有一個非常重要的Bean被注冊了。
~~~
@Configuration
public class WebSecurityConfiguration {
//DEFAULT_FILTER_NAME = "springSecurityFilterChain"
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
...
}
}
~~~
在未使用springboot之前,大多數人都應該對“springSecurityFilterChain”這個名詞不會陌生,他是spring security的核心過濾器,是整個認證的入口。在曾經的XML配置中,想要啟用spring security,需要在web.xml中進行如下配置:
~~~
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
~~~
而在springboot集成之后,這樣的XML被java配置取代。WebSecurityConfiguration中完成了聲明springSecurityFilterChain的作用,并且最終交給DelegatingFilterProxy這個代理類,負責攔截請求(注意DelegatingFilterProxy這個類不是spring security包中的,而是存在于web包中,spring使用了代理模式來實現安全過濾的解耦)。
#### AuthenticationConfiguration
~~~
@Configuration
@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration {
@Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(
ObjectPostProcessor<Object> objectPostProcessor) {
return new AuthenticationManagerBuilder(objectPostProcessor);
}
public AuthenticationManager getAuthenticationManager() throws Exception {
...
}
}
~~~
AuthenticationConfiguration的主要任務,便是負責生成全局的身份認證管理者AuthenticationManager。還記得在《Spring Security(一)–Architecture Overview》中,介紹了Spring Security的認證體系,AuthenticationManager便是最核心的身份認證管理器。
### 3.3 WebSecurityConfigurerAdapter
適配器模式在spring中被廣泛的使用,在配置中使用Adapter的好處便是,我們可以選擇性的配置想要修改的那一部分配置,而不用覆蓋其他不相關的配置。WebSecurityConfigurerAdapter中我們可以選擇自己想要修改的內容,來進行重寫,而其提供了三個configure重載方法,是我們主要關心的:

由參數就可以知道,分別是對AuthenticationManagerBuilder,WebSecurity,HttpSecurity進行個性化的配置。
#### HttpSecurity常用配置
~~~
@Configuration
@EnableWebSecurity
public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**", "/signup", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.anyRequest().authenticated()
.and()
.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.failureForwardUrl("/login?error")
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/index")
.permitAll()
.and()
.httpBasic()
.disable();
}
}
~~~
上述是一個使用Java Configuration配置HttpSecurity的典型配置,其中http作為根開始配置,每一個and()對應了一個模塊的配置(等同于xml配置中的結束標簽),并且and()返回了HttpSecurity本身,于是可以連續進行配置。他們配置的含義也非常容易通過變量本身來推測,
* authorizeRequests()配置路徑攔截,表明路徑訪問所對應的權限,角色,認證信息。
* formLogin()對應表單認證相關的配置
* logout()對應了注銷相關的配置
* httpBasic()可以配置basic登錄
* etc
他們分別代表了http請求相關的安全配置,這些配置項無一例外的返回了Configurer類,而所有的http相關配置可以通過查看HttpSecurity的主要方法得知:

需要對http協議有一定的了解才能完全掌握所有的配置,不過,springboot和spring security的自動配置已經足夠使用了。其中每一項Configurer(e.g.FormLoginConfigurer,CsrfConfigurer)都是HttpConfigurer的細化配置項。
#### WebSecurityBuilder
~~~
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
}
~~~
以筆者的經驗,這個配置中并不會出現太多的配置信息。
#### AuthenticationManagerBuilder
~~~
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("admin").roles("USER");
}
}
~~~
想要在WebSecurityConfigurerAdapter中進行認證相關的配置,可以使用configure(AuthenticationManagerBuilder auth)暴露一個AuthenticationManager的建造器:AuthenticationManagerBuilder 。如上所示,我們便完成了內存中用戶的配置。
細心的朋友會發現,在前面的文章中我們配置內存中的用戶時,似乎不是這么配置的,而是:
~~~
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("admin").roles("USER");
}
}
~~~
如果你的應用只有唯一一個WebSecurityConfigurerAdapter,那么他們之間的差距可以被忽略,從方法名可以看出兩者的區別:使用@Autowired注入的AuthenticationManagerBuilder是全局的身份認證器,作用域可以跨越多個WebSecurityConfigurerAdapter,以及影響到基于Method的安全控制;而 protected configure()的方式則類似于一個匿名內部類,它的作用域局限于一個WebSecurityConfigurerAdapter內部。關于這一點的區別,可以參考我曾經提出的issuespring-security#issues4571。官方文檔中,也給出了配置多個WebSecurityConfigurerAdapter的場景以及demo,將在該系列的后續文章中解讀。
- java
- 設計模式
- 設計模式總覽
- 設計原則
- 工廠方法模式
- 抽象工廠模式
- 單例模式
- 建造者模式
- 原型模式
- 適配器模式
- 裝飾者模式
- 代理模式
- 外觀模式
- 橋接模式
- 組合模式
- 享元模式
- 策略模式
- 模板方法模式
- 觀察者模式
- 迭代子模式
- 責任鏈模式
- 命令模式
- 備忘錄模式
- 狀態模式
- 訪問者模式
- 中介者模式
- 解釋器模式
- 附錄
- JVM相關
- JVM內存結構
- Java虛擬機的內存組成以及堆內存介紹
- Java堆和棧
- 附錄-數據結構的堆棧和內存分配的堆區棧區的區別
- Java內存之Java 堆
- Java內存之虛擬機和內存區域概述
- Java 內存之方法區和運行時常量池
- Java 內存之直接內存(堆外內存)
- JAVA內存模型
- Java內存模型介紹
- 內存模型如何解決緩存一致性問題
- 深入理解Java內存模型——基礎
- 深入理解Java內存模型——重排序
- 深入理解Java內存模型——順序一致性
- 深入理解Java內存模型——volatile
- 深入理解Java內存模型——鎖
- 深入理解Java內存模型——final
- 深入理解Java內存模型——總結
- 內存可見性
- JAVA對象模型
- JVM內存結構 VS Java內存模型 VS Java對象模型
- Java的對象模型
- Java的對象頭
- HotSpot虛擬機
- HotSpot虛擬機對象探秘
- 深入分析Java的編譯原理
- Java虛擬機的鎖優化技術
- 對象和數組并不是都在堆上分配內存的
- 垃圾回收
- JVM內存管理及垃圾回收
- JVM 垃圾回收器工作原理及使用實例介紹
- JVM內存回收理論與實現(對象存活的判定)
- JVM參數及調優
- CMS GC日志分析
- JVM實用參數(一)JVM類型以及編譯器模式
- JVM實用參數(二)參數分類和即時(JIT)編譯器診斷
- JVM實用參數(三)打印所有XX參數及值
- JVM實用參數(四)內存調優
- JVM實用參數(五)新生代垃圾回收
- JVM實用參數(六) 吞吐量收集器
- JVM實用參數(七)CMS收集器
- JVM實用參數(八)GC日志
- Java性能調優原則
- JVM 優化經驗總結
- 面試題整理
- 面試題1
- java日志規約
- Spring安全
- OAtuth2.0簡介
- Spring Session 簡介(一)
- Spring Session 簡介(二)
- Spring Session 簡介(三)
- Spring Security 簡介(一)
- Spring Security 簡介(二)
- Spring Security 簡介(三)
- Spring Security 簡介(四)
- Spring Security 簡介(五)
- Spring Security Oauth2 (一)
- Spring Security Oauth2 (二)
- Spring Security Oauth2 (三)
- SpringBoot
- Shiro
- Shiro和Spring Security對比
- Shiro簡介
- Session、Cookie和Cache
- Web Socket
- Spring WebFlux