JQuery-Ajax跨域请求带Spring认证失败求助
你遇到的核心问题其实是浏览器发送的OPTIONS预检请求被Spring Security拦截返回401,导致后续的实际GET请求根本没机会发送。我们一步步拆解解决:
1. 让Spring Security放行OPTIONS请求
浏览器发起跨域带自定义头(比如Authorization)的请求时,会先发送OPTIONS预检请求——这个请求是不带Authorization头的。但你的Spring Security默认会拦截所有请求,包括OPTIONS,所以直接返回了401,浏览器就判定预检无效,抛出"Response for preflight is invalid (redirect)"错误。
你需要在Spring Security配置里添加规则,允许OPTIONS请求无需认证:
配置类方式(Spring Security 5.x+)
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http // 保留你的其他安全配置 .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 放行所有OPTIONS预检请求 .anyRequest().authenticated() // 其他配置... } }
XML配置方式
<http> <!-- 其他安全配置 --> <intercept-url pattern="/**" method="OPTIONS" access="permitAll"/> <intercept-url pattern="/**" access="authenticated"/> <!-- 其他配置 --> </http>
2. 修正WildFly的CORS配置:Access-Control-Allow-Origin不能用*
注意到你的WildFly配置里Access-Control-Allow-Origin设为*,但你的Ajax请求开启了withCredentials: true——根据CORS规范,当使用withCredentials时,Access-Control-Allow-Origin必须是具体的域名,不能用通配符*。
把配置改成你的前端实际域名:
<response-header name="Access-Control-Allow-Origin" header-name="Access-Control-Allow-Origin" header-value="http://localhost:8081"/>
如果需要支持多个前端域名,可以后续用动态过滤器处理,但先固定成当前测试域名验证效果。
3. 优化预检缓存时间(可选)
你的Access-Control-Max-Age设为1秒,这个时间太短会导致浏览器频繁发送预检请求,建议调整为3600秒(1小时):
<response-header name="Access-Control-Max-Age" header-name="Access-Control-Max-Age" header-value="3600"/>
4. 简化Ajax请求代码
你的Ajax代码里crossDomain: true可以省略——当设置withCredentials: true时,jQuery会自动处理跨域逻辑。另外确认btoa('username:pwd')生成的Base64编码正确(用户名和密码之间的冒号不能遗漏):
$.ajax({ type: 'GET', url: actionURL, xhrFields: { withCredentials: true }, headers: { 'Authorization': 'Basic ' + btoa('username:pwd') }, success: function(data) { console.log('Status: ok' + JSON.stringify(data)); }, error: function (data) { console.log("error!!" + JSON.stringify(data)); } });
验证效果
修改完配置后重启WildFly和前端服务,再观察请求:
- OPTIONS预检请求应该返回200 OK,且不再携带
WWW-Authenticate头 - 实际的GET请求会正常带上Authorization头,返回业务响应
按照这几步操作,应该就能解决你的问题了。
内容的提问来源于stack exchange,提问作者user1632980

