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) {
}
}