我将Spring Boot与Spring Security和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(这是Spring安全中错误身份验证的标准代码)
0
带有以下浏览器通知:
获取http:// localhost:5000 / api / token
XMLHttpRequest无法加载http:// localhost:5000。所请求的资源上不存在“ Access-Control-Allow-Origin”标头。因此,不允许访问源’ http:// localhost:3000 ‘。响应的HTTP状态码为401。
我正在开发前端代码,该代码需要服务器响应中有用的http状态代码来处理这种情况。我需要比0更有用的东西。而且响应主体为空。我不知道我的配置是否错误,或者是软件错误,我也不知道它在哪里(铬(使用arch linux)或spring security)。
我的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 Spring Boot。博客文章写道:
CORS支持将在即将发布的Spring Boot 1.3版本中提供,并且在1.3.0.BUILD-SNAPSHOT版本中已提供。
在Spring Boot应用程序中使用带有@CrossOrigin批注的控制器方法CORS配置不需要任何特定的配置。
可以通过使用自定义的addCorsMappings(CorsRegistry)方法注册WebMvcConfigurer bean来定义全局CORS配置:
我添加了以下代码以启用全局cors支持。实际上,我之前曾经尝试过,但是结果是一样的。我最近再次尝试过,结果是一样的。
@Configuration public class MyConfiguration { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**"); } }; } }
问题来自授权过程之间的重定向,这是一个有趣的想法。我如何更改对任何资源的重定向以避免这种冲突?
编辑:
我想我已经接近解决方案了。我已经通过在所有请求中添加Access-Control-Allow-Origin:*,对支持cors且没有问题的nodejs服务器进行了测试。
就像Stefan Isele已经提到的那样,似乎spring安全性重定向或未添加CORS标头,因此这就是请求似乎被破坏的原因。因此,当spring安全性正在检查身份验证时,它必须添加适当的标头。
有人知道怎么做吗?
为了使其正常工作,你需要按如下所示在Spring Security级别显式启用CORS支持,否则启用CORS的请求可能会在到达Spring MVC之前被Spring Security阻止。
如果使用控制器级别的@CrossOrigin注释,则只需启用Spring Security CORS支持,它将利用Spring MVC配置:
@CrossOrigin
@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and()... } }
如果你更喜欢使用CORS全局配置,则可以声明一个CorsConfigurationSourcebean,如下所示:
CorsConfigurationSource
@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and()... } @Bean CorsConfigurationSource corsConfigurationSource() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues()); return source; } }