小编典典

如何在Spring Boot + Spring Security应用程序中配置CORS?

spring

我将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安全性正在检查身份验证时,它必须添加适当的标头。

有人知道怎么做吗?


阅读 1010

收藏
2020-04-11

共1个答案

小编典典

为了使其正常工作,你需要按如下所示在Spring Security级别显式启用CORS支持,否则启用CORS的请求可能会在到达Spring MVC之前被Spring Security阻止。

如果使用控制器级别的@CrossOrigin注释,则只需启用Spring Security CORS支持,它将利用Spring MVC配置:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()...
    }
}

如果你更喜欢使用CORS全局配置,则可以声明一个CorsConfigurationSourcebean,如下所示:

@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;
    }
}
2020-04-11