修正401与CORS预飞行和春季安全
最后修改:2020年8月5日
1.概述
在这篇简短的教程中,我们将学习如何解决错误“preflight响应具有无效的HTTP状态码401”,这可能发生在支持跨源通信和使用Spring Security的应用程序中。
首先,我们将了解什么是跨源请求,然后我们将修复一个有问题的示例。
2.跨源请求
简而言之,跨源请求是请求的源和目标不同的HTTP请求。例如,当一个web应用程序从一个域提供服务,而浏览器向另一个域的服务器发送AJAX请求时,就是这种情况。
要管理跨源请求,服务器需要启用一种称为CORS或跨源资源共享的特殊机制。
CORS的第一步是选项请求确定请求的目标是否支持它。这被称为飞行前请求。
然后,服务器可以用一组头信息来响应飞行前的请求:
- Access-Control-Allow-Origin:定义哪些源可以访问该资源。A ' *'表示任何原点
- Access-Control-Allow-Methods:允许跨源请求使用的HTTP方法
- Access-Control-Allow-Headers:允许跨源请求的请求头
- Access-Control-Max-Age:定义缓存的飞行前请求的结果的过期时间
因此,如果飞行前的请求不满足从这些响应头确定的条件,实际的后续请求将抛出与跨源请求相关的错误。
很容易将CORS支持添加到spring支持的服务中,但如果配置不正确,此飞行前请求将始终与401失败。
3.创建一个支持cors的REST API
为了模拟这个问题,让我们首先创建一个支持跨源请求的简单REST API:
@RestController @CrossOrigin("http://localhost:4200") public class ResourceController {@GetMapping("/user") public String user(Principal Principal) {return Principal . getname ();}}
的@CrossOrigin注释确保我们的api只能从其参数中提到的源访问。
4.保护我们的REST API
现在让我们用Spring安全保护我们的REST API:
@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Override protected void configure(HttpSecurity http) throws Exception {http .authorizeRequests() .anyRequest().authenticated() .and() .httpBasic();}}
在这个配置类中,我们强制对所有传入请求进行授权。因此,它将拒绝所有没有有效授权令牌的请求。
5.提出飞行前请求
现在我们已经创建了REST API,让我们尝试使用旋度:
curl -v -H "Access-Control-Request-Method: GET" -H "Origin: http://localhost:4200" -X OPTIONS http://localhost:8080/user…< http /1.1 401…< WWW-Authenticate: Basic realm=" realm "…<不同:起源<不同:Access-Control-Request-Method <不同:Access-Control-Request-Headers < Access-Control-Allow-Origin: http://localhost: 4200 < Access-Control-Allow-Methods:文章< Access-Control-Allow-Credentials:真<负责人允许:获取、POST、PUT、DELETE,跟踪,选项,补丁……
从这个命令的输出,我们可以看到这个请求被401拒绝了。
因为这是旋度命令,我们不会在输出中看到错误“preflight的Response has invalid HTTP status code 401”。
但是,我们可以通过创建一个前端应用程序,使用来自不同领域的REST API,并在浏览器中运行它来重现这个错误。
6.解决方案
在Spring Security配置中,我们没有明确地从授权中排除飞行前请求。请记住Spring Security是安全的所有默认的端点。
作为一个结果,我们的API也期望在OPTIONS请求中有一个授权令牌。
Spring提供了一个开箱即用的解决方案,从授权检查中排除OPTIONS请求:
@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Override protected void configure(HttpSecurity http) throws Exception{//…http.cors ();}}
的歌珥()方法将添加spring提供的CorsFilter到应用程序上下文,从而绕过了对OPTIONS请求的授权检查。
现在我们可以再次测试应用程序,看看它是否正常工作。
7.结论
在这篇简短的文章中,我们学习了如何修复错误“preflight响应具有无效的HTTP状态码401”,该状态码与Spring Security和跨源请求链接。
注意,在这个示例中,客户端和API应该运行在不同的域或端口上,以重新创建问题。例如,在本地机器上运行时,我们可以将默认主机名映射到客户机,将机器IP地址映射到REST API。
与往常一样,可以找到本教程中显示的示例在Github。