初始SpringSecurity安全框架
在介紹之前址儒,我們先來體驗一下SpringSecurity。
我們在一個新建springboot2的項目中,來引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- 首先扰付,用戶通過Controller向未授權(quán)的資源發(fā)出未經(jīng)身份驗證的GetMapper請求/private此叠。
- 然后在瀏覽器URL中輸入項目的啟動端口+private纯续,你就會發(fā)現(xiàn)自己跳轉(zhuǎn)到了login登錄頁面,打開idea發(fā)現(xiàn)控制臺多了一串字符串灭袁,通過用戶名=user + 密碼=字符串可以登錄成功猬错,并訪問到private,這就是接下來要講的茸歧。
認證(你是誰?)
表單登錄
本節(jié)檢查基于表單的登錄在 Spring 安全性中的工作原理倦炒。 首先,我們看到用戶如何被重定向到登錄表單:
- 一软瞎、Spring Security的AuthorizationFilter設(shè)置了anyRequest().authenticated(); //默認攔截所有的請求逢唤。
- 二、AuthorizationFilter如果訪問被攔截則會通過ExceptionTranslationFilter(處理安全異常的安全過濾器)處理.AccessDeniedException異常涤浇。
- 三鳖藕、由于用戶未經(jīng)過身份驗證,因此ExceptionTranslationFilter會啟動身份驗證只锭,并使用配置的 AuthenticationEntryPoint 將重定向到登錄頁面著恩。
- 四、重定向到login頁面
用戶提交用戶名和密碼后蜻展,將對用戶名和密碼進行身份驗證喉誊。
身份驗證處理過濾器:
在此攔截器中驗證用戶名和密碼是否正確,并指向到不同的攔截器鏈進行處理铺呵。
授權(quán)(你能做什么)
我們可以使用authorizeHttpRequests來定制不同的放行策略裹驰。
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
http
// ...
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/resources/**", "/signup", "/about").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/db/**").access(new WebExpressionAuthorizationManager("hasRole('ADMIN') and hasRole('DBA')"))
// .requestMatchers("/db/**").access(AuthorizationManagers.allOf(AuthorityAuthorizationManager.hasRole("ADMIN"), AuthorityAuthorizationManager.hasRole("DBA")))
.anyRequest().denyAll()
);
return http.build();
}
- 指定了多個授權(quán)規(guī)則。 每個規(guī)則都按照聲明的順序進行考慮片挂。
- 我們指定了任何用戶都可以訪問的多個 URL 模式幻林。 具體而言贞盯,如果 URL 以“/resources/”開頭、等于“/signup”或等于“/about”沪饺,則任何用戶都可以訪問請求躏敢。
- 任何以“/admin/”開頭的 URL 都將僅限于具有“ROLE_ADMIN”角色的用戶。 您會注意到整葡,由于我們正在調(diào)用該方法件余,因此我們不需要指定“ROLE_”前綴。hasRole
- 任何以“/db/”開頭的 URL 都要求用戶同時具有“ROLE_ADMIN”和“ROLE_DBA”遭居。 您會注意到啼器,由于我們使用的是表達式,因此不需要指定“ROLE_”前綴俱萍。hasRole
- 4中的相同規(guī)則端壳,可以通過組合多個.AuthorizationManager
- 任何尚未匹配的 URL 都將被拒絕訪問。 如果您不想意外忘記更新授權(quán)規(guī)則枪蘑,這是一個很好的策略损谦。
請求匹配
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.securityMatcher("/api/**")
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/user/**").hasRole("USER")
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(withDefaults());
return http.build();
}
}
- 配置為僅應(yīng)用于以HttpSecurity/api/
- 允許具有該角色的用戶訪問以 開頭的網(wǎng)址/user/USER
- 允許具有該角色的用戶訪問以 開頭的網(wǎng)址/admin/ADMIN
- 任何其他不符合上述規(guī)則的請求都需要身份驗證
防范漏洞利用
針對跨站點請求偽造攻擊(CSRF)攻擊
在SpringSecurity中,默認是啟用了防范CSRF策略岳颇,但可以設(shè)置禁用CSRF
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable());
return http.build();
}
}
在 Spring Security 中照捡,專門提供了一個 CsrfFilter 來實現(xiàn)對 CSRF 的保護。CsrfFilter 攔截請求话侧,并允許使用 GET栗精、HEAD、TRACE 和 OPTIONS 等 HTTP 方法的請求掂摔。而針對 PUT术羔、POST赢赊、DELETE 等可能會修改數(shù)據(jù)的其他請求乙漓,CsrfFilter 則希望接收包含 csrf_token 的消息頭。如果這個消息頭不存在或包含不正確的 csrf_token 值释移,應(yīng)用程序?qū)⒕芙^該請求并將響應(yīng)的狀態(tài)設(shè)置為 403叭披。
CSRF攻擊的原理是這樣的:
CSRF的攻擊者只是利用了通過認證的Cookie。
CsrfFilter就在返回給客戶端的表單里隱藏域的Value里和請求頭中放置隨機值玩讳,并在服務(wù)端也放置這個隨機值涩蜘,在用戶發(fā)送請求時來校驗這個隨機值是否正確,如果不正確則拒絕訪問熏纯。
但是在微服務(wù)中不能使用這種方式同诫,因為客戶端訪問了一次實例,下發(fā)了Token樟澜。但微服務(wù)的多模塊及負載均衡的特性误窖,我們下一次攜帶Token發(fā)送的請求叮盘,未必是上一次的實例。
后端可以把隨機字符串存入到Redis里霹俺,響應(yīng)給前端柔吼,前端攜帶字符串訪問Redis來驗證。