spring security 6.0.8(boot 3.0.13)自定義 filter 踩坑-已解決

快乐的凡人721發表於2024-04-03

spring boot 3.0.13(3.1.10)

spring security 6.0.8(6.1.8)

--

官方文件:

https://docs.spring.io/spring-security/reference/index.html

寫文時最新為 6.2.3 。

說明,先是用 spring boot 3.1.10 測試,失敗,降低到 3.0.13 仍然失敗。

開發

建立了 AppLoginFilter,實現了 attemptAuthentication 方法。

在 AppSecurityConfig 配置了:

@Configuration
@RequiredArgsConstructor
@Slf4j
public class AppSecurityConfig {

@Bean
public AppLoginFilter appLoginFilter(AuthenticationManager authenticationManager) throws Exception {
AppLoginFilter appLoginFilter = new AppLoginFilter();

appLoginFilter.setAuthenticationSuccessHandler(new AppLoginSuccessHandler());
appLoginFilter.setAuthenticationFailureHandler(new AppLoginFailureHandler());

appLoginFilter.setAuthenticationManager(authenticationManager);

// todo more

return appLoginFilter;
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http,
AppLoginFilter appLoginFilter,
AuthenticationManager authenticationManager)

throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.csrf(csrf -> csrf.disable())
.cors(cors -> cors.disable())
.addFilterAt(appLoginFilter, UsernamePasswordAuthenticationFilter.class)
.formLogin(formlogin -> formlogin.disable())
.httpBasic(httpbasic -> httpbasic.disable())
;
return http.build();
}
// more
}

登入介面:/app/login。

另外開發了測試介面:/test/getAppName。

發現問題

測試時,/app/login 正常呼叫,也有 Set-Cookie 響應頭。

可是,使用 Set-Cookie 的 Cookie 訪問 /test/getAppName 介面時,被拒絕了。

C:\Users\Mi>curl -v -X POST http://localhost:29001/app/login -H "Content-Type: application/json" -d "{\"username\": \"user\", \"password\":\"111\"}"
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying [::1]:29001...
* Connected to localhost (::1) port 29001
> POST /app/login HTTP/1.1
> Host: localhost:29001
> User-Agent: curl/8.4.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 38
>
< HTTP/1.1 200
< Set-Cookie: JSESSIONID=43935860065AA00C85F6256735D1F368; Path=/; HttpOnly
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 0
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Tue, 02 Apr 2024 14:18:24 GMT
<
{"code":200,"data":true,"message":"登入成功","timestamp":1712067504358}* Connection #0 to host localhost left intact

C:\Users\Mi>
C:\Users\Mi>curl -v http://localhost:29001/test/getAppName -H "Cookie: JSESSIONID=43935860065AA00C85F6256735D1F368"
* Trying [::1]:29001...
* Connected to localhost (::1) port 29001
> GET /test/getAppName HTTP/1.1
> Host: localhost:29001
> User-Agent: curl/8.4.0
> Accept: */*
> Cookie: JSESSIONID=43935860065AA00C85F6256735D1F368
>
< HTTP/1.1 403
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 0
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Length: 0
< Date: Tue, 02 Apr 2024 14:18:42 GMT
<
* Connection #0 to host localhost left intact

後臺出現一條警告日誌:

WARN 5256 --- [io-29001-exec-3] o.s.w.s.h.HandlerMappingIntrospector : Cache miss for REQUEST dispatch to '/test/getAppName' (previous null). Performing MatchableHandlerMapping lookup. This is logged once only at WARN level, and every time at TRACE.

忽略該資訊。

解決方案

給 自定義 filter 設定 SecurityContextRepository 為 HttpSessionSecurityContextRepository 即可。

SecurityContextRepository repo = new HttpSessionSecurityContextRepository();

appLoginFilter.setSecurityContextRepository(repo);

新增後,再次測試,成功。

說明,該方法設定了 AbstractAuthenticationProcessingFilter 的 securityContextRepository 屬性,其預設值為:

private SecurityContextRepository securityContextRepository = new RequestAttributeSecurityContextRepository();

除錯過程

在 自定義的 AppLoginFilter 的 父類 AbstractAuthenticationProcessingFilter#325 中有一個 successfulAuthentication 函式,其中會呼叫:

this.securityContextHolderStrategy.setContext(context);

除錯發現,這裡的 this.securityContextHolderStrategy 值為 RequestAttributeSecurityContextRepository 例項,而不是 HttpSessionSecurityContextRepository 例項。

spring security 6.0.8(boot 3.0.13)自定義 filter 踩坑-已解決

而在 SecurityContextHolderFilter 中,其值為 DelegatingSecurityContextRepository 例項——包含兩個 SecurityContextRepository,其中一個是 HttpSessionSecurityContextRepository 。

spring security 6.0.8(boot 3.0.13)自定義 filter 踩坑-已解決

spring security 6.0.8(boot 3.0.13)自定義 filter 踩坑-已解決

官方文件:SecurityContextRepository

Persisting Authentication # SecurityContextRepository

https://docs.spring.io/spring-security/reference/servlet/authentication/persistence.html

spring security 6.0.8(boot 3.0.13)自定義 filter 踩坑-已解決

The HttpSessionSecurityContextRepository associates the SecurityContext to the HttpSession.

The RequestAttributeSecurityContextRepository saves the SecurityContext as a request attribute to make sure the SecurityContext is available for a single request that occurs across dispatch types that may clear out the SecurityContext.

---END---

ben釋出於部落格園

本文連結:

https://www.cnblogs.com/luo630/p/18111645

ben釋出於部落格園

ben釋出於部落格園

相關文章