Подтверждение поля заголовка запроса не разрешено Access-Control-Allow-Headers в предполетном ответе, даже если сервер уже разрешает это - PullRequest
0 голосов
/ 13 июля 2020

Я знаю, что этот вопрос уже распространяется по всему стековому потоку, но этот совсем другой.

У меня возникла ошибка при попытке использовать java API с помощью ax ios, как показано ниже,

axios
      .get("http://127.0.0.1:8090/api/v1/homescreen")
      .then(response => {
        console.log(response);
      })
      .catch(err => {
        console.log(err);
      });
  }

Ax ios конфигурация была

ax ios .defaults.headers.common ['Content-Type'] = 'application / x- www-form-urlencoded' ; ax ios .defaults.headers.common ['Авторизация'] = 'Носитель eyJhbGciOiJIUzI1N'; ax ios .defaults.headers.common ['Ack'] = 'MTIwNzIwMjBL ==';

Уже пробовал с axios.defaults.headers.common['Content-Type'] = application/json; и получил ту же ошибку.

ошибка была

Доступ к XMLHttpRequest в 'http://127.0.0.1: 8090 / api / v1 / homescreen' from origin 'http://localhost: 8080' был заблокирован политикой CORS: Подтверждение поля заголовка запроса не разрешено Access-Control-Allow-Headers в предполетном ответе.

Теперь на стороне сервера я уже настроил его так

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(Ordered.LOWEST_PRECEDENCE)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    public SecurityConfig() {
        super();
        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http.cors().configurationSource(corsConfigurationSource()).and().csrf().disable()
            .exceptionHandling().and().authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers(HttpMethod.GET, "/api/v1/cache/**").permitAll()
            .antMatchers("/api/v1/**").authenticated().and().authorizeRequests()
            .and().httpBasic();
    }

    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(Arrays.asList("Access-Control-Allow-Headers", 
        "Access-Control-Allow-Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", 
        "Origin", "Cache-Control", "Content-Type", "Authorization", "Ack", "ack", "ackwhatever", "goddamnack"));
        configuration.setAllowedMethods(Arrays.asList("DELETE", "GET", "POST", "PATCH", "PUT"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Override
    public void configure(final WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS).antMatchers("/api/v1/login/*");
    }

    @Override
    protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

даже в весеннем фильтре я поставил Допуск заголовка

public class HttpRequestAuditFilter implements Filter {

    private static final Logger LOG = LoggerFactory.getLogger("access");
    private static final int MAX_PAYLOAD_LENGTH = 10000;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        if ((request instanceof HttpServletRequest)
            && !(request instanceof ContentCachingRequestWrapper)) {
            request = new ContentCachingRequestWrapper((HttpServletRequest) request);
        }

        HttpServletResponse responseQ = (HttpServletResponse) response;
        HttpServletRequest requestQ = (HttpServletRequest) request;

        try {
            responseQ.setHeader("Access-Control-Allow-Origin", "*");
            responseQ.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
            responseQ.setHeader("Access-Control-Max-Age", "3600");
            responseQ.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, content-type, ack, Ack");
            responseQ.setHeader("Access-Control-Expose-Headers", "x-requested-with, authorization, content-type, ack, Ack");

            if ("OPTIONS".equalsIgnoreCase(requestQ.getMethod())) {
                responseQ.setStatus(HttpServletResponse.SC_OK);
            } else {
                chain.doFilter(requestQ, responseQ);
            }

        } finally {
            if (requestQ instanceof HttpServletRequest) {
                performRequestAudit((HttpServletRequest) requestQ);
            }
        }
    }

    public void performRequestAudit(HttpServletRequest httpRequest) {
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(httpRequest, ContentCachingRequestWrapper.class);

        String payload = "";
        if (wrapper != null) {
            byte[] requestBuffer = wrapper.getContentAsByteArray();
            if (requestBuffer.length > 0) {
                int length = Math.min(requestBuffer.length, MAX_PAYLOAD_LENGTH);
                try {
                    payload = new String(requestBuffer,
                        0, length, wrapper.getCharacterEncoding());
                } catch (UnsupportedEncodingException unex) {
                    payload = "[Unsupported-Encoding]";
                }
            }
        }
        LOG.trace("{}|{}", payload, wrapper.getHeaderNames());
    }

}

Когда я пробую с помощью curl, я получил ответ даже в мобильном приложении, он работает отлично, только с браузером, в котором произошла ошибка (сам браузер уже --disable-web-security).

Любая помощь и объяснение будут оценены.

1 Ответ

1 голос
/ 13 июля 2020

Вместо того, чтобы указывать класс конфигурации cors вручную, пусть это будет bean-компонент, и пусть Spring автоматически его берет, а также удалите самый низкий порядок, чтобы ваша конфигурация не была переопределена. Также удалите пружинный фильтр, который вы создали, чтобы вручную добавить заголовки в ответ, так как при правильной настройке Spring Security автоматически добавит эти заголовки в ответ. @EnableGlobalMethodSecurity можно использовать вместе с любыми @Configuration аннотированными классами, но попробуйте следующее:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    public SecurityConfig() {
        super();
        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
            .exceptionHandling().and().authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers(HttpMethod.GET, "/api/v1/cache/**").permitAll()
            .antMatchers("/api/v1/**").authenticated().and().authorizeRequests()
            .and().httpBasic();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(Arrays.asList("Access-Control-Allow-Headers", 
        "Access-Control-Allow-Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", 
        "Origin", "Cache-Control", "Content-Type", "Authorization", "Ack", "ack", "ackwhatever", "goddamnack"));
        configuration.setAllowedMethods(Arrays.asList("DELETE", "GET", "POST", "PATCH", "PUT"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Override
    public void configure(final WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS).antMatchers("/api/v1/login/*");
    }

    @Override
    protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

Если это не сработает, отделите конфигурации безопасности на уровне метода от другого класса конфигурации и сохраните веб-безопасность как отдельная конфигурация.

...