說說如何使用 Spring Security 保護 web 請求
利用 WebSecurityConfigurerAdapter 類的configure(HttpSecurity http) 方法,可以實現以下功能:
- 只有滿足特定條件的請求,才允許提供服務;
- 自定義登入頁;
- 退出賬戶;
- 預防跨站請求偽造。
1 許可權配置
對 HTTP 請求路徑進行許可權配置。假設必須具有 ROLE_USER 角色的賬戶才能訪問 /notice 與 /sms 路徑;而其它路徑無限制。具體配置程式碼如下:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/notice", "/sms")
.hasRole("USER")
.antMatchers("/", "/**").permitAll();
}
注意:
- 這裡順序很重要,因為先宣告的規則比後宣告的規則具有更高的優先順序。
- hasRole() 會自動為入參加上 “ROLE_” 字首,所以我們這裡只傳入 USER 即可。
方法名 | 說明 |
---|---|
access(String) | 如果給定的 SpEL 表示式計算結果為 true ,就允許訪問 |
anonymous() | 允許匿名賬戶訪問 |
authenticated() | 允許認證過的賬戶訪問 |
denyAll() | 拒絕所有訪問 |
fullyAuthenticated() | 如果賬戶是經過完整流程認證的,即非使用 “記住我”功能認證的,就允許訪問 |
hasAnyAuthority(String … ) | 如果賬戶具有給定許可權列表中的某一個許可權,就允許訪問 |
hasAuthority(String) | 如果賬戶具有給定許可權,就允許訪問 |
hasAnyRole(String … ) | 如果賬戶具有給定角色列表中的某一個角色,就允許訪問 |
hasRole(String) | 如果賬戶具有給定角色,就允許訪問 |
hasIpAddress(String) | 如果請求來自於某個給定的 IP 地址,就允許訪問 |
not() | 對前面的判定取反操作 |
permitAll() | 無限制訪問 |
上面這張表中的絕大多數方法都只能完成單一功能,如果需要的安全規則複雜,建議使用 access(String) 方法,這個方法的入參是 SpEL 表示式。Spring Security 還擴充套件了SpEL 表示式,具體說明如下。
安全表示式 | 結果 |
---|---|
authentication | 賬戶的認證物件 |
denyAll | 拒絕訪問,返回 false |
hasAnyRole(roles) | 如果賬戶具有角色列表中任意角色,返回 true |
hasRole(role) | 如果賬戶具有指定角色,返回 true |
hasIpAddress( ip) | 如果請求來自於指定 IP ,返回為 true |
Craig Walls 舉了這樣一個使用安全表示式示例:
http.authorizeRequests()
.antMatchers("/design", "/orders")
.access("hasRole('USER') &&" +
"T(java.util.Calendar).getInstance().get(" +
"T(java.util.Calendar).DAY_OF_WEEK)==" +
"T(java.util.Calendar).TUESDAY");
access() 中的表示式含義是:只允許具有 ROLE_USER 許可權的賬戶在星期二訪問 /design 或 /orders 地址。
2 自定義登入頁
在configure(Http Securityhttp) 方法中,我們還可以自定義登入頁。
http.authorizeRequests()
.antMatchers("/notice", "/sms")
.hasRole("USER")
.antMatchers("/", "/**").permitAll()
.and()
.formLogin()
.loginPage("/login");
這裡通過呼叫formLogin() 方法來實現,loginPage() 方法用於配置登入頁 URL 地址。利用and() 方法,我們可以把配置串聯起來。antMatchers() 方法下的每一段不同型別的配置,都可以通過 and() 進行串聯。
通過這樣配置之後,只要賬戶沒有通過認證,就會將地址重定向到該登入路徑。
因為登入頁只是一個檢視,所以我們可以很簡單地在實現了 WebMvcConfigurer 的 WebConfig 中將其宣告為一個檢視控制器。
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
…
registry.addViewController("/login");
}
}
Spring Security會在指定的登入請求路徑下監聽登入請求,預設的使用者名稱和密碼名稱為 username 和 password。 使用者名稱和密碼引數名稱支援可配置。
http.authorizeRequests()
.antMatchers("/notice", "/sms")
.hasRole("USER")
.antMatchers("/", "/**").permitAll()
//登入頁
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/authenticate")
.usernameParameter("user")
.passwordParameter("pwd");
loginProcessingUrl() 方法用於指定登入請求路徑。usernameParameter() 與passwordParameter() 分別用於自定義使用者名稱和密碼引數名稱。
預設情況下,使用者登入成功之後,將會跳轉到根路徑("/”),一般我們會將其設定為登入後的主頁地址。這個預設的登入成功頁也可自定義。
http.authorizeRequests()
...
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/authenticate")
.usernameParameter("user")
.passwordParameter("pwd")
//登入成功後跳轉頁
.defaultSuccessUrl("/index");
這樣配置之後,只要使用者登入成功,就會跳轉到 “/index”。
defaultSuccessUrl() 方法還提供了一個可選入參(alwaysUse)。如果該引數設定為 True,那麼即使使用者在登入之前正在訪問其他頁面,在登入成功後,也會跳轉到指定頁面。
.defaultSuccessUrl("/index",true);
3 退出賬戶
退出賬戶也是一個常見功能,即使用者點選“登出”按鈕,退出應用。
在 HttpSecurity 物件上,連綴配置登出過濾器,該過濾器會攔截所有針對 “/logout” 的請求。
預設情況下,使用者會被重定向到登入頁,這樣他們就可以重新登入。我們也可以定製登出導航頁,而這是通過 logoutSuccessUrl() 方法來實現的。
http.authorizeRequests()
...
.logout()
.logoutSuccessUrl("/");
4 預防跨站請求偽造
跨站請求偽造(英語:Cross-site request forgery),也被稱為 one-click attack 或者 session riding,通常縮寫為 CSRF 或者 XSRF, 是一種挾制使用者在當前已登入的Web應用程式上執行非本意的操作的攻擊方法。跟跨網站指令碼(XSS)相比,XSS 利用的是使用者對指定網站的信任,CSRF 利用的是網站對使用者網頁瀏覽器的信任。
為了防止CSRF 攻擊,我們可以在表單渲染的時候生成一個 CSRF token,並將其放入表單隱藏域。提交表單時,會把表單資料與這個token一併傳送到服務端。服務端會首先攔截該請求,並與最初生成的 token 進行比對。如果 token 匹配成功,那麼請求將會被轉發到業務層進行後續處理;如果 token 匹配不成功,說明這個可能是惡意請求,服務端將不再轉發。
Spring Security 本身提供了 CSRF 保護,而且預設是啟用狀態。我們只需要在表單中加入一個名為“_csrf”的隱藏域即可,這個隱藏域用於儲存CSRF token。
比如在 Thymeleaf 模板中,可以這樣定義“_csrf” 隱藏域:
< input type=" hidden" name="_ csrf" th: value="${_ csrf. token}"/>
也可以關閉CSRF 保護,在HttpSecurity物件上呼叫 csrf() 方法開啟 CSRF 配置,然後呼叫disable() 方法關閉CSRF:
http.authorizeRequests()
...
.csrf()
.disable();
這一般只適用於開發環境,生產環境還是建議開啟 CSRF保護,保障應用安全。
5 獲取登入賬戶
有以下幾種常用的方式:
- 在 Controller 方法中注入 Principal 物件;
- 在 Controller 方法中注入 Authentication 物件;
- 在 Controller 方法的入參中使用 @AuthenticationPrincipal 註解;
- 使用 SecurityContextHolder。
(1)注入 Principal 物件
在 Controller 方法的入參中直接注入 Principal 物件,然後再通過Principal 物件內的賬戶名獲取 User 物件。
@PostMapping
public String process(@Valid Notice notice, Errors errors, Principal principal) {
...
User user=userRepository.findByUsername(principal.getName());
...
}
這種方式雖然可行,但存在安全程式碼與業務程式碼雜糅的現象。
(2)注入 Authentication物件
在 Controller 方法的入參中直接注入 Authentication物件,然後直接獲取賬戶物件。
@PostMapping
public String process(@Valid Notice notice, Errors errors, Authentication authentication
) {
...
User user= (User) authentication.getPrincipal();
...
}
getPrincipal() 方法返回的是 Object 物件,我們需要將其轉為 User 物件。
(3)使用 @AuthenticationPrincipal 註解
在 Controller 方法的賬戶物件入參中使用 @AuthenticationPrincipal 註解。
@PostMapping
public String process(@Valid Notice notice, Errors errors, @AuthenticationPrincipal User user
) {
...
}
@AuthenticationPrincipal 寫法不需要型別轉換,而且將與安全相關的程式碼限制在賬戶物件上,從而避免了前兩種方式所帶來的問題。另外這種用法也是目前最簡潔的寫法,因此推薦使用。
(4)SecurityContextHolder
可以從SecurityContextHolder中獲取一個 Authentication 物件,然後再獲取其中的 principal。
Authentication authentication= SecurityContextHolder.getContext().getAuthentication();
User user= (User) authentication.getPrincipal();
使用 SecurityContextHolder的好處是:它可以任何地方使用!我們一般會在底層程式碼程式設計中使用到它。
相關文章
- 請你說說SpringSpring
- Spring Security實戰三:說說我的認識Spring
- 使用Spring Security 6.1及更高版本保護Spring Boot 3應用Spring Boot
- 十、Spring Boot整合Spring Security之HTTP請求授權Spring BootHTTP
- 說說 HTTP 常見的請求頭有哪些? 作用?HTTP
- Volley 網路請求框架介紹與使用說明框架
- 說說你對請求數和併發數的理解
- 說說如何在 Spring Boot 中使用 JdbcTemplate 讀寫資料Spring BootJDBC
- spring security:ajax請求的session超時處理SpringSession
- 面試官:說說你對網路請求加密的理解?面試加密
- Go Web如何處理Web請求?GoWeb
- Charles 抓取 https 請求說明文件(mac)HTTPMac
- Spring Boot安全保護使用教程Spring Boot
- 你說說RPC的一個請求的流程是怎麼樣的?RPC
- 請說說DOM節點的操作如何最佳化?
- EOCR-PMZ電機綜合保護器選型使用說明書
- 如何使用spring測試模組測試請求功能Spring
- 公司logo如何申請版權保護Go
- EOCR-3DE電流保護器說明書3D
- 說說如何使用 Python 類的屬性Python
- 說說如何使用 vue-router 外掛Vue
- 說說Darknet 如何和QT qtcreator配置使用QT
- 說一說Web端側AIWebAI
- Spring MVC框架處理Web請求的基本流程SpringMVC框架Web
- Spring Security 前後端分離登入,非法請求直接返回 JSONSpring後端JSON
- 說說在 Spring 中,如何基於 XML 來配置事務SpringXML
- onethink 如何使用get請求?
- 說說Web 無障礙設計Web
- 使用這些 HTTP 頭保護 Web 應用HTTPWeb
- 使用Spring Integration接收TCP與UDP請求SpringTCPUDP
- Spring的@Qualifier註解使用說明Spring
- 請說說json和jsonp的區別?JSON
- 說說在 Spring 中,如何程式設計實現事務管理Spring程式設計
- Web請求過程Web
- 前端專案中如何保證請求時序前端
- 如何從Spring Security 5遷移到Spring Security 6/Spring Boot 3Spring Boot
- 落實等級保護工作的意義簡單說明
- axios取消請求 CancelToken(如何使用)iOS