我使用 Spring 启动,支持 Spring 安全性和 Cors。
如果我执行以下代码
url = 'http://localhost:5000/api/token'
xmlhttp = new XMLHttpRequest
xmlhttp.onreadystatechange = ->
if xmlhttp.readyState is 4
console.log xmlhttp.status
xmlhttp.open "GET", url, true
# xmlhttp.setRequestHeader "X-Requested-With", "XMLHttpRequest"
xmlhttp.setRequestHeader 'Authorization', 'Basic ' + btoa 'a:a'
do xmlhttp.send
我得到的结果
200
如果我使用错误的凭据进行测试,比如
url = 'http://localhost:5000/api/token'
xmlhttp = new XMLHttpRequest
xmlhttp.onreadystatechange = ->
if xmlhttp.readyState is 4
console.log xmlhttp.status
xmlhttp.open "GET", url, true
# xmlhttp.setRequestHeader "X-Requested-With", "XMLHttpRequest"
xmlhttp.setRequestHeader 'Authorization', 'Basic ' + btoa 'a:aa'
do xmlhttp.send
而不是得到401(这是春季安全性中错误身份验证的标准代码)
0
浏览器通知如下:
接通 http://localhost:5000/api/token
XMLHttpRequest 无法加载 http://localhost:5000。请求的资源上没有“访问控制-允许-起源”标头。因此,不允许访问起源“ http://localhost:3000”。反应 HTTP状态码为401。
我正在开发前端代码,需要有用的 http 状态代码从服务器响应来处理这种情况。我需要比0更有用的东西。响应主体也是空的。我不知道如果我的配置是错误的,或者它是一个软件错误,我也不知道在哪里,如果它是铬(使用 arch linux)或春天安全。
我的 Spring 配置是:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@RestController
@RequestMapping("api")
public class Controller {
@RequestMapping("token")
@CrossOrigin
Map<String, String> token(HttpSession session) {
return Collections.singletonMap("token", session.getId());
}
}
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("a").password("a").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.anyRequest().authenticated()
.and().httpBasic();
}
}
如果我使用 curl 进行测试,那么一切都很完美,我认为这是因为不需要 CORS 支持,但是我尝试使用 OPTION 请求模拟 CORS,结果也是可以的。
$ curl -v localhost:5000/api/token -H "Authorization: Basic YTpha"
* Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> GET /api/token HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.48.0
> Accept: */*
> Authorization: Basic YTpha
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Access-Control-Allow-Origin: http://localhost:3000
< Access-Control-Allow-Methods: POST,GET,OPTIONS,DELETE
< Access-Control-Max-Age: 3600
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Origin,Accept,X-Requested- With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization
< x-auth-token: 58e4cca9-7719-46c8-9180-2fc16aec8dff
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sun, 01 May 2016 16:15:44 GMT
<
* Connection #0 to host localhost left intact
{"token":"58e4cca9-7719-46c8-9180-2fc16aec8dff"}
以及错误的证书:
$ curl -v localhost:5000/api/token -H "Authorization: Basic YTp"
* Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> GET /api/token HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.48.0
> Accept: */*
> Authorization: Basic YTp
>
< HTTP/1.1 401 Unauthorized
< Server: Apache-Coyote/1.1
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< WWW-Authenticate: Basic realm="Realm"
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sun, 01 May 2016 16:16:15 GMT
<
* Connection #0 to host localhost left intact
{"timestamp":1462119375041,"status":401,"error":"Unauthorized","message":"Failed to decode basic authentication token","path":"/api/token"}
编辑: 为了避免误解,我使用了1.3.3 SpringBoot。 这篇博文写道:
CORS 支持将在即将发布的 Spring Boot 1.3版本中提供,并且在1.3.0.BUILD-SNAPSHOT 构建中已经提供。
在 Spring Boot 应用程序中使用带有@CrossOrigin 注释的控制器方法 CORS 配置不需要任何特定的配置。
全局 CORS 配置可以通过使用定制的 addCorsMaps (CorsRegistry)方法注册 WebMvcConfigurerbean 来定义:
我添加了以下代码以启用全局 cors 支持。实际上我以前试过,但结果是一样的。我最近又试了一次,结果还是一样。
@Configuration
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
}
但是,认为问题来自授权过程之间的重定向是一个有趣的想法。我如何改变重定向到任何资源,以避免这种冲突?
编辑:
我想我快找到解决办法了。我已经测试了我的 nodejs 服务器,它通过添加 访问-控制-允许-来源: * 所有的要求。
就像 Stefan Isele 已经提到的那样,似乎春季安全重定向或不添加 CORS 头,所以这就是为什么请求似乎被破坏了。因此,当 Spring 安全性检查身份验证时,它必须添加适当的头。
有人知道怎么做吗?
编辑:
我找到了一个变通方案,看起来很难看。我已经开始了一个针对春季启动的 github 问题,在这里我描述了解决方案: https://github.com/spring-projects/spring-boot/issues/5834