我有一个 Spring Boot 应用程序,它使用 spring security 作为依赖项。我正在将 Spring boot 版本从 2.7.16 迁移到 3.2.1。在 2.7.16 版本中一切正常。但在 3.2.1 中,其余 API 过了一会儿就会给出 403。有时5分钟后,有时1小时后。因此,一开始它会给出 200 成功响应,但一段时间后会给出 403。经过多次尝试后我无法解决该问题。我正在分享安全配置。任何帮助表示赞赏
2.7.16安全配置;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService;
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@RequiredArgsConstructor
public class SecurityConfiguration {
private final AuthenticationConfiguration configuration;
@Bean
protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/h2-console/**").permitAll()
.antMatchers("/manage/info").permitAll()
.antMatchers("/manage/health").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(authenticationFilter())
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.and()
.headers().frameOptions().disable();
return http.build();
}
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return configuration.getAuthenticationManager();
}
@Bean
public RequestHeaderAuthenticationFilter authenticationFilter() throws Exception {
RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
filter.setPrincipalRequestHeader(HeaderConstants.PRINCIPAL_HEADER);
filter.setExceptionIfHeaderMissing(false);
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationDetailsSource(new HeaderAuthenticationDetailsSource());
return filter;
}
@Bean
public PreAuthenticatedAuthenticationProvider authenticationProvider() {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(new PreAuthenticatedGrantedAuthoritiesUserDetailsService());
return provider;
}
}
这是 3.2.1 安全配置;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService;
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;
import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {
private final AuthenticationConfiguration configuration;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers(antMatcher("/h2-console/**")).permitAll()
.requestMatchers(antMatcher("/manage/info")).permitAll()
.requestMatchers(antMatcher("/manage/health")).permitAll()
.anyRequest().authenticated()
)
.addFilter(authenticationFilter())
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
;
return http.build();
}
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return configuration.getAuthenticationManager();
}
@Bean
public RequestHeaderAuthenticationFilter authenticationFilter() throws Exception {
RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
filter.setPrincipalRequestHeader(HeaderConstants.PRINCIPAL_HEADER);
filter.setExceptionIfHeaderMissing(false);
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationDetailsSource(new HeaderAuthenticationDetailsSource());
return filter;
}
@Bean
public PreAuthenticatedAuthenticationProvider authenticationProvider() {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(new PreAuthenticatedGrantedAuthoritiesUserDetailsService());
return provider;
}
}
日志:
2024-01-05T18:59:40.276Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-01-05T18:59:40.279Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.security.web.FilterChainProxy : Securing GET /error
2024-01-05T18:59:40.281Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.security.web.FilterChainProxy : Secured GET /error
2024-01-05T18:59:40.282Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for GET "/error", parameters={}
2024-01-05T18:59:40.282Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
2024-01-05T18:59:40.283Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
2024-01-05T18:59:40.284Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/cbor]
2024-01-05T18:59:40.285Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Writing [{timestamp=Fri Jan 05 18:59:40 GMT 2024, status=403, error=Forbidden, path=/worklogEntries/health}]
2024-01-05T18:59:40.288Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
2024-01-05T18:59:40.288Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 403
好的,我找到答案了。为了解决这个问题,我必须设置 SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);显式地在 SecurityConfig 类的 SecurityFilterChain 方法中。该值是默认值,但它在我的项目中的其他地方被覆盖。这在 2.7 版本中不是问题,但现在是 3 版本中的问题。
感谢这篇帖子