java - Spring Boot permitAll 在 WebSecurityConfigurerAdapter 中不起作用

标签 java spring-boot spring-security

当我 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

最佳答案

configure(HttpSecurity http) 中使用 .csrf().disable() 禁用 CSRF 更多详细信息已说明 here

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
           .csrf().disable()
           ... // other configurations
}

关于java - Spring Boot permitAll 在 WebSecurityConfigurerAdapter 中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64981098/

相关文章:

java - Spring Boot 和 Gradle 多模块项目,未能正确加载依赖项

java - 如何在 Spring Boot 中手动验证用户身份?

java - (Java) 数组越界异常

java - 设置 JAVA_HOME 与 JRE_HOME 与 PATH 环境变量

api - 考虑在您的配置中定义类型为 'javax.servlet.ServletContext' 的 bean

spring-boot - Spring Boot 2.0.4 - H2 数据库 - @SpringBootTest - 因 : org. h2.jdbc.JdbcSQLException 导致失败:未找到架构 "classpath:db/schema.sql"

java - spring security中,如何判断session是否因多次登录而失效?

java - 无法在 Netbeans 中使用 gradle 传递 JVM 参数。创建名称为 'springSecurityFilterChain' 的 bean 时出错

java - 无法从生产环境中的数据源确定 jdbc url

java - (撒克逊 dtd)java.net.SocketException : Unexpected end of file fromserver