Spring websocket issues

49 views Asked by At

it's the first time I've used websocket in spring... I created a microservices app and now I need to use websockets to create a very simple notification system...

I don't know if this would be a good idea but I'm trying to use a rest API to call my websocket like this:

`public class RestController { @Autowired private WSService wsService;

@PostMapping("/send-message")
public void sendMessage(@RequestBody final Message message){
    wsService.notifyFrontend(message.getContent());
}

@PostMapping("/send-private-message/{id}")
public void sendPrivateMessage(@PathVariable final String id, @RequestBody final Message message){
    wsService.notifyUser(id, message.getContent());
}

}`

with this service:

@Service
public class WSService {

    private final SimpMessagingTemplate simpMessagingTemplate;

    @Autowired
    public WSService(SimpMessagingTemplate simpMessagingTemplate) {
        this.simpMessagingTemplate = simpMessagingTemplate;
    }

    public void notifyFrontend(final String message){

        ResponseMessage responseMessage = new ResponseMessage("response "+message);

        simpMessagingTemplate.convertAndSend("/topic/messages", responseMessage);
    }

    public void notifyUser(final String id, final String message){

        ResponseMessage responseMessage = new ResponseMessage("private response "+message);

        simpMessagingTemplate.convertAndSendToUser(id, "/topic/messages", responseMessage);
    }
}

and finally the WSController here:

@Controller
public class WebSocketController {
    @MessageMapping("/message")
    @SendTo("/topic/messages")
    public ResponseMessage getMessage(final Message message) throws InterruptedException {
        Thread.sleep(1000);
        return new ResponseMessage(HtmlUtils.htmlEscape(message.getContent()));
    }
    @MessageMapping("/private-message")
    @SendToUser("/topic/private-messages")
    public ResponseMessage getPrivateMessage(final Message message,final Principal principal) throws InterruptedException {
        Thread.sleep(1000);
        return new ResponseMessage(HtmlUtils.htmlEscape("private : "+principal.getName()+" : "+message.getContent()));
    }
}

I dont know if the pattern it could be good or i should call my websocket from other microservices using rabbitMQ instead of feign client....
Whats is the best way for set userID for private messages?

**
Im using a simple keycloak jwt for the auth in my project
and now im trying to set the userId like session principal from the claim of the jwt in the header of the handshake
with this custom handshakehandler:**

@Component
public class CustomHandShakeHandler extends DefaultHandshakeHandler {
    private JwtService jwtService;
    public CustomHandShakeHandler(JwtService jwtService){
        this.jwtService=jwtService;
    }
    protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
        return new UserPrincipal(jwtService.extractUserID(request));
    }
}

/


@Service
public class JwtService {
    @Value("${keycloak.publicKeyString}")
    private String publicKeyString;
    public static String extractToken(ServerHttpRequest request) {
        System.out.println(1);
        List<String> authorizationHeaders = request.getHeaders().get("Authorization");
        System.out.println(authorizationHeaders);
        if (authorizationHeaders != null && !authorizationHeaders.isEmpty()) {
            System.out.println(2);
            String authorizationHeader = authorizationHeaders.getFirst();
            if (authorizationHeader.startsWith("Bearer ")) {
                System.out.println(authorizationHeader);
                return authorizationHeader.substring(7);
            }
        }
        return null;
    }
    public Claims extractClaims(String token) {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(publicKeyString);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            Jws<Claims> claimsJws = Jwts.parserBuilder().setSigningKey(publicKey).build().parseClaimsJws(token);
            return claimsJws.getBody();
        }catch (Exception e){
            System.out.println(e);
            return null;
        }
    }
    public String extractUserID(ServerHttpRequest request) {
        String JWT=extractToken(request);
        Claims claims=extractClaims(JWT);
        if (claims.getExpiration().before(Date.from(Instant.now()))) {
            throw new RuntimeException("Token expired");
        }
        return (String) claims.get("name");
    }
}

but i cant get:

List<String> authorizationHeaders = request.getHeaders().get("Authorization");

Its always null
im trying to send it with this simple js code:

        var token="mytoken"       
        var header={
            Authorization: "Bearer " + token
        }
        var socket = new SockJS("http://localhost:8091/websocket");
        var stompClient = Stomp.over(socket);
        stompClient.connect(header, function(frame) {
        });

i DON'T KNOW WHAT THE BUG IS IN SENDING THE TOKEN

AND I DON'T EVEN KNOW IF I'M ON THE RIGHT PATH OR IF I'M JUST MAKING A DISASTER BY DOING EVERYTHING WRONG

0

There are 0 answers