繁体   English   中英

预检响应中的 Access-Control-Allow-Headers 不允许请求 header 字段 ack 即使服务器已经允许它

[英]Request header field ack is not allowed by Access-Control-Allow-Headers in preflight response even the server already allowing it

我知道这个问题已经遍布整个 stackoverflow,但这个问题完全不同。

尝试使用 axios 击中 java API 时出现错误,方法如下,

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

Axios配置分别

axios.defaults.headers.common['Content-Type'] = 'application/x-www-form-urlencoded'; axios.defaults.headers.common['Authorization'] = '承载 eyJhbGciOiJIUzI1N'; axios.defaults.headers.common['Ack'] = 'MTIwNzIwMjBL==';

已经尝试使用axios.defaults.headers.common['Content-Type'] = application/json; 并得到同样的错误。

错误是

Access to XMLHttpRequest at 'http://127.0.0.1:8090/api/v1/homescreen' from origin 'http://localhost:8080' has been blocked by CORS policy: Request header field ack is not allowed by Access-Control - 预检响应中的允许标头。

现在在服务器端我已经像这样配置它

@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();
    }
}

即使在 spring 过滤器中,我也放了 header 余量

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)。

任何帮助和解释将不胜感激。

与其手动提供 cors 配置 class ,不如让它成为一个 bean 并让 spring 自动占用它,同时删除最低顺序,以免您的配置被覆盖。 还要删除您创建的 spring 过滤器以手动在响应中添加标头,因为正确配置时 spring 安全将自动添加这些标头作为响应。 @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();
    }
}

如果这不起作用,请将方法级别的安全配置分离到另一个配置 class 并将 web 安全作为单独的配置。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM