[英]Request header field is not allowed by Access-Control-Allow-Headers in preflight response
[英]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.