CORS issues when connecting to a WebSocket for SpringBoot + React projects

30 views Asked by At

im trying to implement a collaborative whiteboard using a spring boot. so i created WebMvcConfig and applied cors settings.


import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    private final long MAX_AGE_SECS = 3600;
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000")
                .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(MAX_AGE_SECS);
    }


}

Like this. However, when trying to connect to a websocket, a cors error occurs even though I set up a cors.

error> Access to XMLHttpRequest at 'http://localhost:8080/ws/info?t=1710105975151' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Room.jsx:14

   GET http://localhost:8080/ws/info?t=1710105975151 net::ERR_FAILED 403 (Forbidden)

I don't know why I'm getting this error...

im using JWT in my project, and the JWT validation logic is working fine. This is front-end code,


import { useRef, useEffect } from 'react';
import SockJS from 'sockjs-client';
import Canvas from './Canvas';
import {ACCESS_TOKEN} from "../constants";

function Room() {

    const socket = useRef(null);

    useEffect(() => {
        const token = localStorage.getItem(ACCESS_TOKEN);
        socket.current = new SockJS('http://localhost:8080/ws', null, {
            headers: {
                Authorization: 'Bearer ' + token,
            }
        });
        socket.current.onopen = () => {
            socket.current.send(JSON.stringify({
                type: 'auth',
                token
            }));
        };
        return () => {
            socket.current.close();
        }
    }, []);

    const handleDraw = (x, y) => {
        const msg = JSON.stringify({type:'draw', x, y});
        socket.current.send(msg);
    }

    return (
        <div>
            <Canvas
                socket={socket.current}
                onDraw={handleDraw}
            />
        </div>
    )

}

export default Room;

and This is the socket endpoint setup from springboot

package com.lsm.backend.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.setApplicationDestinationPrefixes("/app");

    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").withSockJS();

    }

}

I keep getting CORS errors no matter what I try I think it's an authentication problem I tried making jwt authentication logic in sockethandler, but it doesn't work.

package com.lsm.backend.socket;

import com.alibaba.fastjson.JSON;
import com.lsm.backend.security.CustomUserDetailsService;
import com.lsm.backend.security.TokenProvider;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import com.alibaba.fastjson.JSONObject;
@Component
@RequiredArgsConstructor
public class SocketHandler extends TextWebSocketHandler {
    private final TokenProvider tokenProvider;
    private static final Logger logger = LoggerFactory.getLogger(TokenProvider.class);

    private final CustomUserDetailsService customUserDetailsService;
    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) {
        JSONObject json = (JSONObject) JSON.parse(message.getPayload());

        if(json.getString("type").equals("auth")) {
            String jwt = json.getString("token");
            try{
                tokenProvider.validateToken(jwt);
                Long userId = tokenProvider.getUserIdFromToken(jwt);
                UserDetails userDetails = customUserDetailsService.loadUserById(userId);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

                SecurityContextHolder.getContext ().setAuthentication(authentication);
            } catch (Exception ex) {
                logger.error("Could not set user authentication in security context", ex);
            }


        }
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) {

    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
       
    }
}
0

There are 0 answers