java spring angular auth0 sockjs

java - El encabezado en la respuesta no debe ser el comodín ''*'' cuando el modo de credenciales de la solicitud es ''incluir''



spring angular (4)

Esto no tiene nada que ver con su código de aplicación angular o de primavera.

Introducción a tu problema
Access-Control-Allow-Origin es una parte del mecanismo CORS (Intercambio de recursos de origen cruzado) que proporciona a los servidores web controles de acceso entre dominios. Está en su lugar para proteger su aplicación / sitio de CSRF (falsificación de solicitud entre sitios) .

CORS / CSRF

El problema
Ahora si leemos tu error cuidadosamente

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.

Dice que el encabezado Access-Control-Allow-Origin no puede ser un comodín.

En otras palabras, ahora su back-end está diciendo que todos, desde cualquier lugar de la web, pueden ejecutar código en mi sitio.

Lo que queremos lograr : Limite el origen solo a su aplicación de front-end (ng2).

Solución Ahora, debido a que está utilizando Spring, asumiré que lo está utilizando con Apache Tomcat como su servidor web back-end.

Los CORS se definen como filtro en su web.conf (carpeta tomcat)

encuentra esta linea

<init-param> <param-name>cors.allowed.origins</param-name> <param-value>*</param-value> </init-param>

y cambia el * a localhost:4200

Para más información sobre la configuración de CORS en Tomcat , lea esto

EDITAR (arranque de primavera)
Debido a que está utilizando Spring Boot, puede delegar la configuración de cors en el marco.

Por favor, siga este tutorial en spring.io (como el chsdk propuesto) para obtener una mejor comprensión de la configuración de CORS con la bota de resorte.

Estoy usando Auth0 para mi autenticación de usuario para permitir que solo los usuarios registrados puedan acceder a un RestController Spring (Boot). En este punto, estoy creando una funcionalidad de mensajes en tiempo real donde los usuarios pueden enviar mensajes desde el cliente Angular 2 ( localhost:4200 ) al servidor Spring (localhost: 8081) usando stompjs y sockjs .

Al intentar crear un cliente Stomp e iniciar una conexión, recibo el siguiente error de consola:

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.

Después de investigar este problema, parece que no es posible configurar la opción origins = * y credentials = true al mismo tiempo. ¿Cómo puedo resolver esto cuando ya he establecido el origen permitido en WebSocketConfig para el dominio del cliente?

Componente 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(); } }

localhost: 8081 / chat / info? t = 1490866768565

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

Controlador de mensajes

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

SecurityConfig (temporalmente permite todos)

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

ACTUALIZAR

Después de algunas pruebas e investigaciones adicionales, parece que el problema solo ocurre con Chrome. El problema puede estar relacionado con: https://github.com/sockjs/sockjs-node/issues/177

ACTUALIZAR

Creé el CORSFilter como mencionó chsdk y usé el método 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(); }

Puedo ver que se llama al filtro mediante su depuración, pero el mensaje de error sigue apareciendo en el lado del cliente, incluso si se establece el correcto Access-Control-Allow-Origin:


Mi respuesta es demasiado tarde, pero estoy publicando esto si alguien pudiera enfrentar el mismo problema, he estado enfrentando el mismo problema de origen cruzado.

Básicamente, si está utilizando Spring Security implementado en su aplicación del lado del servidor, es probable que sea él quien bloquee el handshaker websocket

Debe indicar a la seguridad de Spring que permita los puntos finales de sus websocket para permitir el protocolo de enlace de socket ... usando

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

Así que sockjs ahora podrá enviar una solicitud GET (Http) para el protocolo de intercambio antes de cambiar al protocolo Websocket.

Esta es la configuración de seguridad de 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(); }}

Esta es la configuración de 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"); } }


Simplemente agregue .setAllowedOrigins("*") a la configuración de webSocket.

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

La versión de webSocket es 1.4.1.RELEASE, debe actualizar su versión si no se muestra el método.


Problema:

No está configurando ''Access-Control-Allow-Origin'' correctamente y el servidor simplemente ignora su configuración actual.

Situación:

La traza de pila de error dice:

El valor del encabezado ''Access-Control-Allow-Origin'' en la respuesta no debe ser el comodín ''*'' cuando el modo de credenciales de la solicitud es ''include''. Por lo tanto, el origen '' localhost:4200 '' no tiene acceso permitido.

Significa que, aparte del hecho de que no puede establecer ''Access-Control-Allow-Origin'' en el comodín "*" , su dominio ''http://localhost:4200'' no tiene acceso permitido.

Para responder tu pregunta:

¿Cómo puedo resolver esto cuando ya he establecido el origen permitido en WebSocketConfig para el dominio del cliente?

Solución:

Supongo que no es necesario establecer el origen permitido en WebSocketConfig ya que está diseñado para configurar los mensajes de estilo WebSocket en las aplicaciones web como se indica en la documentación de WebSocket Support en Spring. para configurar Spring Filters para el acceso a aplicaciones web.

Esto es lo que necesitará en su clase de configuración 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<String> 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) { } }

Puedes ver el uso de:

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

Para establecer la lista de dominios permitidos para acceder al servidor.

Referencias:

Es posible que deba consultar el soporte de CORS en Spring Framework y habilitar las solicitudes de origen cruzado para un servicio web RESTful para obtener más información al respecto.