当请求的凭据模式为“include”时,响应中的标头不能是通配符“*”

我正在使用Auth0进行用户身份validation,只允许登录用户访问Spring(Boot) RestController 。 此时我正在创建一个实时消息function,用户可以使用stompjssockjs将消息从Angular 2客户端( localhost:4200 )发送到Spring服务器(localhost:8081)。

尝试创建Stomp客户端并启动连接时,我收到以下控制台错误:

  The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:4200' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute. 

在研究了这个问题之后,看起来无法同时设置选项origins = *和credentials = true。 当我已经将WebSocketConfig中允许的原点设置为客户端域时,如何解决此问题?

Angular 2组件

 connect() { var socket = new SockJS('http://localhost:8081/chat'); this.stompClient = Stomp.over(socket); this.stompClient.connect({}, function(result) { console.log('Connected: ' + result); this.stompClient.subscribe('/topic/messages', function(message) { console.log(message); }); }); } 

WebSocketConfig

 @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/chat").setAllowedOrigins("http://localhost:4200").withSockJS(); } } 

本地主机:8081 /聊天/信息T = 1490866768565

 {"entropy":-1720701276,"origins":["*:*"],"cookie_needed":true,"websocket":true} 

MessageController

 public class MessageController { @MessageMapping("/chat") @SendTo("/topic/messages") public Message send(Message message) throws Exception { return new Message(message.getFrom(), message.getText()); } } 

SecurityConfig(暂时允许所有)

 public class SecurityConfig extends Auth0SecurityConfig { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().permitAll(); } } 

UPDATE

经过一些更多的测试和研究后,似乎问题只发生在Chrome上。 问题可能与以下内容有关: https : //github.com/sockjs/sockjs-node/issues/177

UPDATE

我创建了像chsdk提到的CORSFilter并使用了addFilterBefore()方法: https ://stackoverflow.com/a/40300363/4836952。

 @Bean CORSFilter corsFilter() { CORSFilter filter = new CORSFilter(); return filter; } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(corsFilter(), SessionManagementFilter.class).authorizeRequests().anyRequest().permitAll(); http.csrf().disable(); } 

我可以看到通过调试它来调用Filter,但即使设置了正确的Access-Control-Allow-Origin,错误消息仍会出现在客户端上:

在此处输入图像描述

问题:

您没有正确配置'Access-Control-Allow-Origin' ,服务器会忽略您当前的配置。

情况:

错误堆栈跟踪说:

当请求的凭据模式为“include”时,响应中'Access-Control-Allow-Origin'标头的值不能是通配符'*' ”。 因此不允许来源’ http:// localhost:4200 ‘访问。

这意味着除了您不能将'Access-Control-Allow-Origin'设置为通配符"*" ,您的域'http://localhost:4200'也不允许访问。

回答你的问题:

当我已经将WebSocketConfig中允许的原点设置为客户端域时,如何解决此问题?

解:

我猜你不需要在WebSocketConfig设置允许的原点,因为它意味着在Web应用程序中配置WebSocket样式的消息传递,如Spring文档中的WebSocket支持中所述,您需要在CORSFilter配置类中配置它,因为它意味着配置Spring Filters以进行Web应用程序访问。

这是您在CORSFilter.java配置类中需要的CORSFilter.java

 public class CORSFilter implements Filter { // This is to be replaced with a list of domains allowed to access the server //You can include more than one origin here private final List allowedOrigins = Arrays.asList("http://localhost:4200"); public void destroy() { } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { // Lets make sure that we are working with HTTP (that is, against HttpServletRequest and HttpServletResponse objects) if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; // Access-Control-Allow-Origin String origin = request.getHeader("Origin"); response.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(origin) ? origin : ""); response.setHeader("Vary", "Origin"); // Access-Control-Max-Age response.setHeader("Access-Control-Max-Age", "3600"); // Access-Control-Allow-Credentials response.setHeader("Access-Control-Allow-Credentials", "true"); // Access-Control-Allow-Methods response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); // Access-Control-Allow-Headers response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, " + "X-CSRF-TOKEN"); } chain.doFilter(req, res); } public void init(FilterConfig filterConfig) { } } 

你可以看到使用:

 private final List allowedOrigins = Arrays.asList("http://localhost:4200"); 

设置允许访问服务器的域列表。

参考文献:

您可能需要查看Spring Framework中的CORS支持以及为RESTful Web服务启用跨源请求以进一步阅读它。

这与您的弹簧或角度应用程序代码无关。

介绍你的问题
Access-Control-Allow-Origin是CORS (跨源资源共享)机制的一部分,它为Web服务器提供跨域访问控制。 它可以保护您的应用/网站免受CSRF (跨站点请求伪造)的侵害。

CORS / CSRF

问题
现在,如果我们仔细阅读您的错误

 The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:4200' is therefore not allowed access. 

它说Access-Control-Allow-Origin标头不能是通配符。

换句话说,现在你的后端正在说每个人都可以在我的网站上运行代码。

我们想要实现的目标 :将原点仅限于您的前端应用程序(ng2)。

解决方案现在,因为您正在使用Spring,我将假设您将它与Apache Tomcat一起用作后端Web服务器。

CORS在web.conf(tomcat文件夹)中被定义为filter

找到这一行

  cors.allowed.origins *  

并将*更改为http:// localhost:4200

有关Tomcat中CORS配置的更多信息, 请阅读此内容

编辑 (春季启动)
因为您使用的是spring boot,所以可以将cors的配置委派给框架。

请按照spring.io 上的本教程 (如chsdk建议),通过spring boot更好地掌握CORS配置。

我的答案为时已晚,但如果有人遇到同样的问题,我会发布这个问题,我一直面临同样的跨领域问题。

基本上,如果您使用在服务器端应用程序上实现的Spring Security,可能是他阻止了websocket握手

您必须告诉Spring安全性允许您的websocket端点以允许套接字握手…使用

 .antMatchers("/socket/**").permitAll() 

所以sockjs现在能够在切换到Websocket协议之前发送握手的GET(Http)请求

这是Spring安全配置

 package org.souhaib.caremy.security.module.config; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint).and() .authorizeRequests() .antMatchers(SecurityParams.PUBLIC_ROUTES).permitAll() .antMatchers("/socket/**").permitAll(); http.csrf().disable(); }} 

这是WebSocket Broker配置

 @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/socket") .setAllowedOrigins("http://localhost:4200") .withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.setApplicationDestinationPrefixes("/app") .enableSimpleBroker("/chat"); } } 

只需在webSocket配置中添加.setAllowedOrigins("*")即可。

 @Override public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) { stompEndpointRegistry.addEndpoint("/yourEndpoint"); stompEndpointRegistry.addEndpoint("/yourEndpoint").setAllowedOrigins("*").withSockJS(); } 

webSocket的版本是1.4.1.RELEASE,如果没有显示方法,你应该更新你的版本。