Spring Boot permitAll 在 WebSecurityConfigurerAdapter 中不起作用
Posted
技术标签:
【中文标题】Spring Boot permitAll 在 WebSecurityConfigurerAdapter 中不起作用【英文标题】:Spring Boot permitAll not working in WebSecurityConfigurerAdapter 【发布时间】:2021-03-06 22:00:08 【问题描述】:当我 POST 到 /api/v1/auth/register
时,我收到了配置的 accessDeniedHandler
生成的 403 响应。但是,我希望这个请求会被允许,因为它被 permitAll()
覆盖并且在 anyRequest().authenticated()
之前。
GET /api/v1/reference/countries
之类的请求可以正常工作。此外,命中这些/api/v1/auth/**
端点的集成测试也可以工作,这表明与 CORS 有关,尽管预检请求是 200。
知道这个安全配置有什么问题吗?
@Configuration
@EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true
)
@Order(1)
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter
private final UserDetailsServiceImpl userDetailsService;
private final Config config;
private final ObjectMapper objectMapper;
@Override
protected void configure(HttpSecurity http) throws Exception
http
.cors()
.and()
.authorizeRequests()
.antMatchers(
"/api/v1/auth/register",
"/api/v1/auth/register/check",
"/api/v1/auth/register/activate",
"/api/v1/auth/password/update",
"/api/v1/auth/recover",
"/api/v1/auth/recover/check",
"/api/v1/auth/recover/reset",
"/api/v1/csrf-token",
"/api/v1/reference/**"
)
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.successHandler((request, response, authentication) ->
response.getWriter().append("OK");
response.setStatus(HttpServletResponse.SC_OK);
)
.failureHandler((request, response, exception) ->
response.getWriter().append("Invalid credentials or inactive account");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
)
.loginProcessingUrl("/api/v1/auth/login")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/api/v1/auth/logout", "POST"))
.permitAll()
.and()
.exceptionHandling()
.accessDeniedHandler((request, response, accessDeniedException) ->
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
objectMapper.writeValue(
response.getWriter(),
ErrorResponseBody
.builder()
.code(ErrorType.ACCESS_DENIED)
.status(HttpServletResponse.SC_FORBIDDEN)
.message("Access denied")
.build()
);
)
.authenticationEntryPoint((request, response, authException) ->
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
objectMapper.writeValue(
response.getWriter(),
ErrorResponseBody
.builder()
.code(ErrorType.LOGIN_REQUIRED)
.status(HttpServletResponse.SC_UNAUTHORIZED)
.message("You are not authorized to access this resource")
.build()
);
)
.and()
.userDetailsService(userDetailsService);
if (config.isCsrfDisabled())
http
.csrf()
.disable();
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(userDetailsService);
@Bean
public BCryptPasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder();
@Bean
public CorsConfigurationSource corsConfigurationSource()
final var configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.setAllowedOrigins(config.getAllowedOrigins());
configuration.setAllowedMethods(asList("GET", "POST", "PUT", "PATCH", "DELETE"));
configuration.setAllowedHeaders(Arrays.asList(HttpHeaders.AUTHORIZATION, HttpHeaders.CACHE_CONTROL, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT));
final var source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", configuration);
return source;
这是我的 CORS 配置:
@Configuration
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class WebConfig
private final Config config;
@Bean
public WebMvcConfigurer corsConfigurer()
return new WebMvcConfigurer()
@Override
public void addCorsMappings(CorsRegistry registry)
final var allowedOrigins = Optional
.ofNullable(config.getAllowedOrigins())
.map(origins -> origins.toArray(new String[]))
.orElse(new String[]);
System.out.println("Enabling CORS for the following origins:" + Arrays.asList(allowedOrigins).toString());
registry
.addMapping("/api/**")
.allowedOrigins(allowedOrigins)
.allowCredentials(true)
.allowedMethods("*")
.allowedHeaders("*");
;
我从http://localhost:3000
调用这些端点,这是config.getAllowedOrigins()
返回的项目之一。
这是来自请求的 Spring Security 调试日志:
2020-11-24 06:51:16.110 INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-11-24 06:51:16.112 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-11-24 06:51:16.158 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 44 ms
2020-11-24 06:51:16.193 DEBUG 1 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-11-24 06:51:16.200 DEBUG 1 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-11-24 06:51:16.205 DEBUG 1 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2020-11-24 06:51:16.206 DEBUG 1 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2020-11-24 06:51:16.214 DEBUG 1 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-11-24 06:51:16.217 DEBUG 1 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 4 of 13 in additional filter chain; firing Filter: 'CorsFilter'
2020-11-24 06:51:16.286 DEBUG 1 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@461bbc94
2020-11-24 06:51:16.290 DEBUG 1 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-11-24 06:51:16.299 DEBUG 1 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2020-11-24 06:51:16.483 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-11-24 06:51:16.485 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-11-24 06:51:16.486 DEBUG 1 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2020-11-24 06:51:16.487 DEBUG 1 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2020-11-24 06:51:16.488 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-11-24 06:51:16.489 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 4 of 13 in additional filter chain; firing Filter: 'CorsFilter'
2020-11-24 06:51:16.494 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 5 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2020-11-24 06:51:16.525 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.csrf.CsrfFilter : Invalid CSRF token found for http://dev.api.example.com/api/v1/auth/register
2020-11-24 06:51:16.609 DEBUG 1 --- [nio-8080-exec-2] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@461bbc94
2020-11-24 06:51:16.610 DEBUG 1 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-11-24 06:51:16.615 DEBUG 1 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
【问题讨论】:
您是否尝试过为 Spring Security 启用调试日志记录?这能说明问题吗? 为 Spring Security 启用调试日志记录后,请求挂起然后超时。 看起来熵不足与启用日志记录同时发生。 【参考方案1】:在configure(HttpSecurity http)
中使用.csrf().disable()
禁用CSRF 更多细节在here 中解释
@Override
protected void configure(HttpSecurity http) throws Exception
http
.csrf().disable()
... // other configurations
【讨论】:
谢谢。我选择了选项 2。选项 1 不是一个好主意,因为 ti 完全禁用了网络安全。很高兴接受这个答案,去掉了选项 1。 是的,configure(WebSecurity web)
理想情况下应该用于静态内容。以上是关于Spring Boot permitAll 在 WebSecurityConfigurerAdapter 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
带有 RequestHeaderMatcher 的 Spring Boot Security PermitAll 不起作用
即使使用 permitall antMatchers,Spring boot Oauth 2 配置也会导致 401
Spring Security permitAll()不匹配排除网址[重复]
Spring Boot Security 基于角色的访问控制