I'm using Auth0
for my user authentication to only allow logged in users to access a Spring (Boot) RestController
. At this point I'm creating a real-time message functionality where users can send messages from the Angular 2
client (localhost:4200
) to the Spring server (localhost:8081) using stompjs
and sockjs
.
When trying to create a Stomp-client and starting a connection I receive the following console-error:
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.
After researching this problem it looks like it is not possible to set the option origins = * and credentials = true at the same time. How can I resolve this when I've already set the allowed origin in the WebSocketConfig to the client domain?
Angular 2 component
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();
}
}
localhost:8081/chat/info?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 (temporarily permits all)
public class SecurityConfig extends Auth0SecurityConfig {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll();
}
}
UPDATE
After some more testing and researching it seems that the problem only happens using Chrome. Problem maybe related to: https://github.com/sockjs/sockjs-node/issues/177
UPDATE
I created the CORSFilter like chsdk mentioned and used the addFilterBefore() method: 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();
}
I can see that the Filter is called by debugging it but the error message keeps appearing on the clientside even if the correct Access-Control-Allow-Origin gets set:
This has nothing to do with your spring or angular app code.
Intro to your problem
The Access-Control-Allow-Origin is a part of CORS (Cross-Origin Resource Sharing) mechanism that gives web servers cross-domain access controls. It is in place to protect your app/site from CSRF (Cross-Site Request Forgery).
CORS / CSRF
The problem
Now if we read your error carefully
It says that Access-Control-Allow-Origin header cannot be a wildcard.
With other words, now your back-end is saying everybody from allover the web can run code on my site.
What we want to achieve: Limit the origin to only your front-end app (ng2).
Solution Now because you are using Spring I will assume that you are using it with Apache Tomcat as your back-end webserver.
CORS are difined as filter in your web.conf (tomcat folder)
find this line
and change the * to http://localhost:4200
for more information about config of CORS in Tomcat please read this
EDIT ( Spring boot )
Because you are using spring boot, you can delegate configuration of cors to the framework.
Please follow this tutorial on spring.io ( like chsdk proposed )to get a better grasp of CORS configuration with spring boot .
Just add
.setAllowedOrigins("*")
at webSocket config.The version of webSocket is 1.4.1.RELEASE,you should update your version if the method wasn't shown.
my answer is too late but i'm posting this if anyone could face the same problem, i've been facing the same cross-origin issue.
Basically if you are using Spring Security implemented on your server side application, Probably it is he who blocks websocket handshaker
You have to tell Spring security to allow your websocket endpoints in order to allow socket handshake... using
So sockjs will be able now to send a GET (Http) request for handshaking before switching to Websocket protocol
This is Spring security Configuration
This is WebSocket Broker configuration
Problem:
You are not configuring
'Access-Control-Allow-Origin'
correctly and your current configuration is simply ignored by the server.Situation:
The Error stack trace says:
It means that apart from the fact that you can't set
'Access-Control-Allow-Origin'
to the wildcard"*"
, your domain'http://localhost:4200'
is not allowed access too.To answer your question:
Solution:
I guess you don't need to set the allowed origin in the
WebSocketConfig
because it's meant to configure WebSocket-style messaging in web applications as stated in WebSocket Support in Spring documentation, you will need to configure it in aCORSFilter
configuration class as it's meant to configure Spring Filters for Web application access.This is what you will need in your
CORSFilter.java
configuration class:You can see the use of :
To set the list of domains allowed to access the server.
References:
You may need to take a look at CORS support in Spring Framework and Enabling Cross Origin Requests for a RESTful Web Service for further reading about it.