在 Spring Security 6 中(特别是 Spring Boot 3.2,在我的例子中是带有 Thymeleaf 的 Spring MVC),当使用 securityMatcher 时,默认的 /logout POST 或 GET 将停止工作。
@Bean
public SecurityFilterChain openFilterChain(HttpSecurity http) throws Exception {
http.securityMatcher("/EParticipate/baudit/**")
.addFilterBefore(new BauditUsernamePasswordAuthenticationFilter(
this.authenticationManager(userDetailsService, passwordEncoder())),
UsernamePasswordAuthenticationFilter.class
)
.authorizeHttpRequests((requests) -> requests
.dispatcherTypeMatchers(DispatcherType.FORWARD, DispatcherType.ERROR).permitAll()
.requestMatchers("/EParticipate/baudit/**").hasRole("BAUDIT")
.requestMatchers("/EParticipateSecurity/**").permitAll()
)
.authenticationManager(this.authenticationManager(userDetailsService, passwordEncoder()))
.formLogin(form -> form
.loginPage("/EParticipateSecurity/login_request").permitAll()
.defaultSuccessUrl("/EParticipate/baudit")
)
return http.build();
}
以及 Thymeleaf 中的 POST 链接:
<form id="logout_form" th:action="@{/logout}" method="POST">
<button id="logout_button" type="submit">Logout</button>
</form>
即使你在requestMatcher中添加了
permitAll()
,它仍然不起作用:
@Bean
public SecurityFilterChain openFilterChain(HttpSecurity http) throws Exception {
http.securityMatcher("/EParticipate/baudit/**")
.addFilterBefore(new BauditUsernamePasswordAuthenticationFilter(
this.authenticationManager(userDetailsService, passwordEncoder())),
UsernamePasswordAuthenticationFilter.class
)
.authorizeHttpRequests((requests) -> requests
.dispatcherTypeMatchers(DispatcherType.FORWARD, DispatcherType.ERROR).permitAll()
.requestMatchers("/EParticipate/baudit/**").hasRole("BAUDIT")
//Doesn't work
.requestMatchers("/EParticipateSecurity/**","/logout").permitAll()
)
.authenticationManager(this.authenticationManager(userDetailsService, passwordEncoder()))
.formLogin(form -> form
.loginPage("/EParticipateSecurity/login_request").permitAll()
.defaultSuccessUrl("/EParticipate/baudit")
)
return http.build();
}
为了解决这个问题,我必须在 securityMatcher 的 URL 下添加一个自定义注销作为子 URL(我还添加了一个注销处理程序以确保注销时清除所有内容)。
@Bean
public SecurityFilterChain openFilterChain(HttpSecurity http) throws Exception {
http.securityMatcher("/EParticipate/baudit/**")
.addFilterBefore(new BauditUsernamePasswordAuthenticationFilter(
this.authenticationManager(userDetailsService, passwordEncoder())),
UsernamePasswordAuthenticationFilter.class
)
.authorizeHttpRequests((requests) -> requests
.dispatcherTypeMatchers(DispatcherType.FORWARD, DispatcherType.ERROR).permitAll()
.requestMatchers("/EParticipate/baudit/**").hasRole("BAUDIT")
.requestMatchers("/EParticipateSecurity/**").permitAll()
)
.authenticationManager(this.authenticationManager(userDetailsService, passwordEncoder()))
.formLogin(form -> form
.loginPage("/EParticipateSecurity/login_request").permitAll()
.defaultSuccessUrl("/EParticipate/baudit")
)
.logout((logout) -> logout
.addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(Directive.CACHE,Directive.COOKIES,Directive.EXECUTION_CONTEXTS,Directive.STORAGE)))
.logoutUrl("/EParticipate/baudit/logout")//URL under the securityMatcher URL above
.logoutSuccessUrl("/EParticipateSecurity/login_request").permitAll()
);
return http.build();
}