Spring Security權限控制系列(一)

環境:Springboot2.4.12 + Spring Security 5.4.9
本篇主要內容是基于內存的配置
引入依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId></dependency>
自定義用戶配置
spring: security: user: name: admin password: 123456
定義Controller接口
("/demos")public class DemoController { ("home") public Object home() { return "demos home" ; }}
訪問:
http://localhost:8080/demos/home。
將會自動跳轉到默認地登錄頁面:

使用配置文件中配置的admin/123123進行登錄。

沒有任何問題
再定義一個POST接口。
@PostMapping("post")public Object post() { return "demos post" ;}注意:這里我們通過Postman訪問默認的登錄/login接口先進行登錄,登錄完成后我們在訪問這個post接口。(記住我們在上面訪問的GET /demos/home接口只要登錄后就可以繼續訪問該接口)。

首次登錄時注意返回的登錄頁面的html內容,表單信息中多了一個隱藏域_csrf字段,如果我們通過Postman模擬登錄時如果不帶上該字段將無法登錄。

修改登錄信息添加上_csrf表單字段,再進行登錄。

這里返回404狀態碼是由于我們沒有配置默認登錄成功頁
到此在Postman中就登錄成功了,接下來咱們繼續通過Postman訪問GET /demos/home接口。

直接訪問沒有任何問題
接著訪問上面定義的POST /demos/post接口。

服務端返回403拒絕訪問,上面GET方式正常,POST出現該異常,接著將上面我們登錄時候的_csrf字段一起進行提交。

針對POST請求必須攜帶正確的_csrf信息才能繼續方法。
實現原理
在默認情況下Security會添加CsrfFilter過濾器。
public final class CsrfFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 從默認的HttpSessionCsrfTokenRepository中獲取token,默認是從session中 CsrfToken csrfToken = this.tokenRepository.loadToken(request); boolean missingToken = (csrfToken == null); if (missingToken) { // 如果當前session不存在則生成token csrfToken = this.tokenRepository.generateToken(request); // 如果csrfToken不為null,則這里什么都不做(不會保存) this.tokenRepository.saveToken(csrfToken, request, response); } // ... // 判斷當前的請求方法是否是("GET", "HEAD", "TRACE", "OPTIONS") // 如果是上面的Method則直接放行,否則繼續往下執行 if (!this.requireCsrfProtectionMatcher.matches(request)) { filterChain.doFilter(request, response); return; } // 從請求header中獲取_csrf值,headerName = X-CSRF-TOKEN String actualToken = request.getHeader(csrfToken.getHeaderName()); if (actualToken == null) { // 如果header中不存在,則從請求參數中獲取 parameterName = _csrf actualToken = request.getParameter(csrfToken.getParameterName()); } // 判斷當前參數中的token值與保存到當前session中的是否想到,不等則返回403錯誤 if (!equalsConstantTime(csrfToken.getToken(), actualToken)) { AccessDeniedException exception = (!missingToken) ? new InvalidCsrfTokenException(csrfToken, actualToken) : new MissingCsrfTokenException(actualToken); this.accessDeniedHandler.handle(request, response, exception); return; } filterChain.doFilter(request, response); }}
一般我們都會關閉csrf功能。
class SecurityConfig extends WebSecurityConfigurerAdapter { protected void configure(HttpSecurity http) throws Exception { // 關閉csrf,就是刪除CsrfFilter過濾器。 http.csrf().disable() ; // 攔截任意請求 http.authorizeRequests().anyRequest().authenticated() ; // 這里需要加上該句,否則不會出現登錄頁面 http.formLogin() ; }}
以上是關于Spring Security默認配置的情況下csrf相關問題。接下來通過自定義類配置來設定用戶的用戶信息。
自定義配置
class SecurityConfig extends WebSecurityConfigurerAdapter { ("deprecation") protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 這在后續的文章中會介紹該方法的具體使用 // super.configure(auth); // 配置用戶名密碼角色,及密碼編碼方式 auth.inMemoryAuthentication().passwordEncoder(NoOpPasswordEncoder.getInstance()).withUser("guest").password("123456").roles("ADMIN") ; } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() ; http.authorizeRequests().anyRequest().authenticated() ; http.formLogin() ; }}
通過上面配置后,在進行授權的時候就需要使用這里的配置信息。
本篇介紹到這里,下篇將介紹具體的請求攔截配置及自定義登錄頁面等功能更。































