【发布时间】:2020-07-13 05:57:44
【问题描述】:
我知道这个问题已经遍布整个 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'] = '应用程序/x-www-form-urlencoded'; axios.defaults.headers.common['Authorization'] = 'Bearer eyJhbGciOiJIUzI1N'; axios.defaults.headers.common['Ack'] = 'MTIwNzIwMjBL==' ;
已经尝试使用axios.defaults.headers.common['Content-Type'] = application/json; 并得到同样的错误。
错误是
在“http://127.0.0.1:8090/api/v1/homescreen”访问 XMLHttpRequest 来自原点“http://localhost:8080”已被 CORS 策略阻止: 请求头字段 ack 不允许 预检响应中的 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)。
任何帮助和解释都将不胜感激。
【问题讨论】:
-
为什么您的安全配置类的优先级最低?如果您已经配置了弹簧安全性,为什么还要有一个弹簧过滤器来添加标题作为响应。如果您使用 cors 配置 spring security,则不需要过滤器。
-
@Ananthapadmanabhan 看到我正在尽一切努力使这个 axios 工作,所以我的代码有点混乱,但仍然可读
-
已经尝试过
Ordered.HIGHEST_PRECEDENCE仍然遇到同样的错误 -
还要在此处与配置类一起提供@WebSecurity注解。
标签: java node.js spring spring-boot axios