Spring Security的配置機制早就變了,你發現了嗎?
以前胖哥說過SecurityConfigurerAdapter會在即將發布的5.7版本作廢,從Spring Security 5.4版本開始會提供一個原型范圍的HttpSecurity來幫助我們構建過濾器鏈SecurityFilterChain:
@Bean(HTTPSECURITY_BEAN_NAME)
@Scope("prototype")
HttpSecurity httpSecurity() throws Exception {
WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder = new WebSecurityConfigurerAdapter.LazyPasswordEncoder(
this.context);
AuthenticationManagerBuilder authenticationBuilder = new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(
this.objectPostProcessor, passwordEncoder);
authenticationBuilder.parentAuthenticationManager(authenticationManager());
HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
// @formatter:off
http
.csrf(withDefaults())
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling(withDefaults())
.headers(withDefaults())
.sessionManagement(withDefaults())
.securityContext(withDefaults())
.requestCache(withDefaults())
.anonymous(withDefaults())
.servletApi(withDefaults())
.apply(new DefaultLoginPageConfigurer<>());
http.logout(withDefaults());
// @formatter:on
return http;
}
這里會構建基于原型的HttpSecurityBean,并且初始化了一些默認配置供我們來使用。涉及Spring Security的日常開發都是圍繞這個類進行的,所以這個類是學習Spring Security的重中之重。
基于原型(prototype)的Spring Bean的一個典型應用場景。
基本配置
日常我們使用的一些配置項如下:
方法 說明
requestMatchers() 為SecurityFilterChain提供URL攔截策略,具體還提供了antMatcher和mvcMathcer
openidLogin() 用于基于 OpenId 的驗證
headers() 將安全標頭添加到響應,比如說簡單的 XSS 保護
cors() 配置跨域資源共享( CORS )
sessionManagement() 配置會話管理
portMapper() 配置一個PortMapper(HttpSecurity#(getSharedObject(class))),其他提供SecurityConfigurer的對象使用 PortMapper 從 HTTP 重定向到 HTTPS 或者從 HTTPS 重定向到 HTTP。默認情況下,Spring Security使用一個PortMapperImpl映射 HTTP 端口8080到 HTTPS 端口8443,HTTP 端口80到 HTTPS 端口443
jee() 配置基于容器的預認證。在這種情況下,認證由Servlet容器管理
x509() 配置基于x509的預認證
rememberMe 配置“記住我”的驗證
authorizeRequests() 基于使用HttpServletRequest限制訪問
requestCache() 配置請求緩存
exceptionHandling() 配置錯誤處理
securityContext() 在HttpServletRequests之間的SecurityContextHolder上設置SecurityContext的管理。當使用WebSecurityConfigurerAdapter時,這將自動應用
servletApi() 將HttpServletRequest方法與在其上找到的值集成到SecurityContext中。當使用WebSecurityConfigurerAdapter時,這將自動應用
csrf() 添加 CSRF 支持,使用WebSecurityConfigurerAdapter時,默認啟用
logout() 添加退出登錄支持。當使用WebSecurityConfigurerAdapter時,這將自動應用。默認情況是,訪問URL”/ logout”,使HTTP Session無效來清除用戶,清除已配置的任何#rememberMe()身份驗證,清除SecurityContextHolder,然后重定向到/login?success
anonymous() 配置匿名用戶的表示方法。當與WebSecurityConfigurerAdapter結合使用時,這將自動應用。默認情況下,匿名用戶將使用org.springframework.security.authentication.AnonymousAuthenticationToken表示,并包含角色 ROLE_ANONYMOUS
authenticationManager() 配置AuthenticationManager
authenticationProvider() 添加AuthenticationProvider
formLogin() 指定支持基于表單的身份驗證。如果未指定FormLoginConfigurer#loginPage(String),則將生成默認登錄頁面
oauth2Login() 根據外部OAuth 2.0或OpenID Connect 1.0提供程序配置身份驗證
oauth2Client() OAuth2.0 客戶端相關的配置
oauth2ResourceServer() OAuth2.0資源服務器相關的配置
requiresChannel() 配置通道安全。為了使該配置有用,必須提供至少一個到所需信道的映射
httpBasic() 配置 Http Basic 驗證
addFilter() 添加一個已經在內置過濾器注冊表注冊過的過濾器實例或者子類
addFilterBefore() 在指定的Filter類之前添加過濾器
addFilterAt() 在指定的Filter類的位置添加過濾器
addFilterAfter() 在指定的Filter類的之后添加過濾器
and() 連接以上策略的連接器,用來組合安全策略。實際上就是”而且”的意思
高級玩法
新手建議先把上面的基本玩法有選擇的弄明白,然后有精力的話去研究下HttpSecurity的高級玩法。
apply
這個方法用來把其它的一些配置合并到當前的配置中去,形成插件化,支持SecurityConfigurerAdapter或者SecurityConfigurer的實現。其實內置的一些配置都是以這種形式集成到HttpSecurity中去的。例如文章開頭的配置中有默認登錄頁面相關的配置:
httpSecurity.apply(new DefaultLoginPageConfigurer<>());
胖哥就利用這個搞了一個支持小程序登錄和驗證碼登錄的擴展 spring-security-login-extension。
objectPostProcessor配置一個自定義ObjectPostProcessor。ObjectPostProcessor可以改變某些配置內部的機制,這些配置往往不直接對外提供操作接口。
獲取、移除配置類
getConfigurer用來獲取已經apply的配置類;getConfigurers用來獲取已經apply某個類型的所有配置類。這個現在是我最喜歡的自定義的方式。
配置、獲取SharedObjectShared
Object是在配置中進行共享的一些對象,HttpSecurity共享了一些非常有用的對象可以供各個配置之間共享,比如AuthenticationManager。相關的方法有setSharedObject、getSharedObject、getSharedObjects。
獲取SecurityFilterChainHttpSecurity也提供了構建目標對象SecurityFilterChain的實例的方法。你可以通過build()來對配置進行初次構建;也可以通過getObject()來獲取已經構建的實例;甚至你可以使用getOrBuild()來進行直接獲取實例或者構建實例。
所以新的配置都是這樣的:
@Bean
SecurityFilterChain securityFilterChain (HttpSecurity http) {
http.cors();
return http.build();
}
記住每一個HttpSecurity只能被構建成功一次。
這一篇非常重要本篇東西非常重要,不是馬上就能掌握的,需要有些耐心,需要在使用和學習中總結和發現。