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

标签 javascript spring spring-security spring-boot cors

我使用带有 Spring Security 和 Cors 支持的 Spring Boot。

如果我执行以下代码

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 Security 中错误身份验证的标准代码)

0

带有以下浏览器通知:

获取 http://localhost:5000/api/token

XMLHttpRequest 无法加载 http://localhost:5000 .请求的资源上不存在“Access-Control-Allow-Origin” header 。产地'http://localhost:3000 ' 因此不允许访问。响应的 HTTP 状态代码为 401。

我正在开发前端代码,需要来自服务器响应的有用 http 状态代码来处理这种情况。我需要比 0 更有用的东西。响应正文也是空的。我不知道我的配置是错误的,还是软件错误,我也不知道是 Chrome (使用arch linux)还是 Spring 安全。

我的 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 support will be available in the upcoming Spring Boot 1.3 release, and is already available in the 1.3.0.BUILD-SNAPSHOT builds.

Using controller method CORS configuration with @CrossOrigin annotations in your Spring Boot application does not require any specific configuration.

Global CORS configuration can be defined by registering a WebMvcConfigurer bean with a customized addCorsMappings(CorsRegistry) method:

我添加了以下代码以启用全局 cors 支持。实际上我以前试过这个,但结果是一样的。我最近又试了一次,结果还是一样。

@Configuration
public class MyConfiguration {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**");
            }
        };
    }
}

虽然问题来自授权过程之间的重定向,但这个想法很有趣。如何更改重定向到任何资源以避免这种冲突?

编辑:

我想我离解决方案更近了。我已经使用支持 cors 的 nodejs 服务器进行了测试,通过添加 访问控制允许来源:* 对所有请求。

就像 Stefan Isele 已经提到的,似乎 spring 安全重定向或不添加 CORS header ,所以这就是请求似乎被破坏的原因。因此,当 Spring Security 检查身份验证时,它必须添加正确的 header 。

有人知道怎么做吗?

编辑:

我找到了一种解决方法,这似乎很难看。我已经为 spring boot 启动了一个 github 问题,我在其中描述了解决方法:https://github.com/spring-projects/spring-boot/issues/5834

最佳答案

Spring Security 现在可以利用 this blog post 中描述的 Spring MVC CORS 支持我写的。

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

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

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

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

如果您更喜欢使用 CORS 全局配置,您可以声明一个 CorsConfigurationSource bean,如下所示:

@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;
    }
}

这种方法取代了 filter-based approach以前推荐过。

您可以在 dedicated CORS section 中找到更多详细信息的 Spring Security 文档。

关于javascript - 如何在 Spring Boot + Spring Security 应用程序中配置 CORS?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36968963/

相关文章:

javascript - Postgres - 使用什么列类型来存储嵌套数组

java - 向现有 @Entity 添加新字段时出现 SQLException (jpa)

java - 字符串数据,右截断 - Hibernate with Spring Boot

java - 解密在 Android 设备上加密的字符串

javascript - 无法使用 OpenLayers 3 站点中的 WFS 示例作为基础加载另一个 WFS

javascript - 如何使用javascript从优酷播放视频?

spring mvc 注释验证整数

spring-security - InMemoryTokenStore 如何与 Spring Security OAuth2 配合使用,从黑客的角度来看,这是最安全的方法吗?

jsf - 清除 h :messages after page refresh

javascript - Antlr4 Javascript 目标 - 访客问题和标记替代方案