Logo

dev-resources.site

for different kinds of informations.

Spring Boot WebSockets: Socket.io + Authentication + Postman

Published at
9/9/2024
Categories
socketio
springboot
springsecurity
websocket
Author
ratnesh_2003
Author
12 person written this
ratnesh_2003
open
Spring Boot WebSockets: Socket.io + Authentication + Postman

Hello folks!! We all know HTTP requests just work fine, they might not be optimal for real-time interactions. This is where WebSockets come in. They offer fast and more efficient way to communicate. Ready to level up your skills? Let's jump into the tutorial and explore how to use WebSockets in Spring Boot using Socket.io alongwith Authentication.

Prerequisites

Before diving in, make sure you have the following things in place:

  1. Java 17+
  2. Maven: We'll be using Maven as our build and dependency management tool
  3. IDE: Choose any IDE you're comfortable with like IntelliJ IDEA or Eclipse.

Also, I presume you have basic understanding of WebSockets and Socket.IO to follow along smoothly. If you are new to these concepts, you can checkout the following resources:

Note: I have uploaded the complete code for the demonstration in this GitHub repository.

Setting Up The Project

  1. Open your IDE, create a new Maven project and configure the project's GroupID, ArtificatID and other details.
  2. Now open the pom.xml file and add the following dependencies under the <dependencies>...</dependencies> tag.

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
        <groupId>com.corundumstudio.socketio</groupId>
        <artifactId>netty-socketio</artifactId>
        <version>2.0.11</version>
    </dependency>
    
    <dependency>
        <groupId>io.socket</groupId>
        <artifactId>socket.io-client</artifactId>
        <version>2.1.1</version>
    </dependency>
    
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.34</version>
        <scope>provided</scope>
    </dependency>
    
    
  3. Just save the pom.xml file, reload Maven and it will automatically download the required dependencies.

Creating WebSocket Configuration

  1. Create a WebSocket configuration class, for example, SocketIOConfig. Add the following properties to it:

    package com.ratnesh.demowebsocketapplication.config;
    
    import com.corundumstudio.socketio.SocketIOServer;
    import lombok.RequiredArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component
    @RequiredArgsConstructor
    @Slf4j
    public class SocketIOConfig {
    
        // I have set the configuration values in application.yaml file
        @Value("${socket.host}")
        private String socketHost;
        @Value("${socket.port}")
        private int socketPort;
    
        // SocketIOServer class is used to create a socket server
        private SocketIOServer server;
    
    }
    
    
  2. You can configure your application.yaml file like this:

    socket:
      host: localhost
      port: 8081
    
  3. Now that we have setup the basic structure of the config class, we will add a bean method under the same class that will initialize the SocketIO server instance, setting it up with specified host and port, enabling bidirectional connections to our application.

    @Bean
    public SocketIOServer socketIOServer() {
        // Configuration object holds the server settings
        Configuration config = new Configuration();
    
        config.setHostname(socketHost);
        config.setPort(socketPort);
    
        server = new SocketIOServer(config);
        server.start();
    
        server.addConnectListener(client -> log.info("Client connected: {}", client.getSessionId()));
        server.addDisconnectListener(client -> log.info("Client disconnected: {}", client.getSessionId()));
    
        return server;
    } 
    
  4. We will add just one more method in the same class right before we end up setting the configuration and that is:

    @PreDestroy
    public void stopSocketServer() {
        this.server.stop();
    }
    
  5. So what above piece of code does is, whenever there is a call to shut down the Spring Container, @PreDestroy annotation calls the method to which it is annotated. As a result, it will ensure to close the SocketIO server properly before shutting down the application, implementing a better clean-up mechanism.

  6. At this point, we can test if we were able to configure our application correctly through postman. Now fire-up your postman, go to New -> Socket.IO and this will open up an untitled Socket.IO request. Enter your URL as localhost:8081 and hit Connect.
    Tada!! You're now connected to your socket server which you can check in your server logs as well.

Image showing how to connect to WebSocket through Postman

Adding Controller

Now, let's create the controller which will actually manage the connection and events. We can configure one or more controllers depending upon the requirements. To configure a controller you can follow the steps:

  1. Create a class, for example, WebSocketController, which is going to manage our socket events. Add the following properties and methods as below:

    package com.ratnesh.demowebsocketapplication.controller;
    
    import com.corundumstudio.socketio.AckRequest;
    import com.corundumstudio.socketio.SocketIOClient;
    import com.corundumstudio.socketio.SocketIOServer;
    import com.corundumstudio.socketio.listener.DataListener;
    import com.ratnesh.demowebsocketapplication.model.SocketDetail;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    
    @Component
    @Slf4j
    public class WebSocketController {
    
        protected final SocketIOServer socketServer;
    
        public WebSocketController(SocketIOServer socketServer) {
            this.socketServer = socketServer;
            this.socketServer.addEventListener("demoEvent", SocketDetail.class, demoEvent);
        }
    
        public DataListener<SocketDetail> demoEvent = new DataListener<>() {
            @Override
            public void onData(SocketIOClient client, SocketDetail socketDetail, AckRequest ackRequest) {
                log.info("Demo event received: {}", socketDetail);
                // Add your business logic here.
                ackRequest.sendAckData("Demo event received");
            }
        };
    }
    
    
  2. Here, we have a demoEvent method which represents an event and it returns an instance of type DataListener<SocketDetail> where SocketDetail is a model class containing a single field called name. Then we are adding this event listener to our socketServer instance through the constructor method.

    package com.ratnesh.demowebsocketapplication.model;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class SocketDetail {
        private String name;
    }
    
  3. You can add up your business logic as per your requirements and add more event listeners to the class.

Testing the Controller

Okay, so before we start authenticating our WebSocket connections with Spring Security, let's check out to see if our controller works fine up until this point. To do this, start your server and open your Postman.

  1. Connect to the server using the host and port specified in your configuration, e.g. localhost and 8081.
  2. Once you are connected with it, select JSON from the message type drop down and pass the body as shown in the image.
  3. Write the name of the event in the Event Name field and select the Ack option. Image showing how to connect and invoke events through Postman
  4. After hitting Send, you'll be getting an acknowledgement from the server that your request was received successfully. You are now successfully connected to the socket server and can communicate bidirectionally.

Authenticating WebSocket Connections

NOTE: I won't be going into full depth on how to authenticate using JWTs. Instead, I'll be using dummy values with a lose approach to authenticate users.

  1. You can set an Authorization Listener through the config in the SocketIOConfig class object which can be used to authenticate the connections like this:

    @Bean
    public SocketIOServer socketIOServer() {
        // Configuration object holds the server settings
        Configuration config = new Configuration();
    
        config.setHostname(socketHost);
        config.setPort(socketPort);
    
        // Authorization listener
        config.setAuthorizationListener(data -> {
            String token = data.getHttpHeaders().get("User-Name");
            if (!token.isEmpty()) {
                // You can extract user information from token using your JWTTokenUtil class and validate it
                // or throw error if token is invalid
                // you can pass more information in headers like role, email, etc.
                // data object can be used to add custom headers after authorization
                data.getHttpHeaders().add("User", "userDetailsAfterAuthorization");
                return new AuthorizationResult(true);
            }
            return new AuthorizationResult(false);
        });
    
        server = new SocketIOServer(config);
        server.start();
    
        server.addConnectListener(client -> log.info("Client connected: {}", client.getSessionId()));
        server.addDisconnectListener(client -> log.info("Client disconnected: {}", client.getSessionId()));
    
        return server;
    }
    
  2. This setup allows you to access the headers and retrieve user information during WebSocket communication. For example, if we need to access the headers in the WebSocketController class that we created, we can modify our demoEvent to something like this:

    public DataListener<SocketDetail> demoEvent = new DataListener<>() {
        @Override
        public void onData(SocketIOClient client, SocketDetail socketDetail, AckRequest ackRequest) {
            log.info("Demo event received: {}", socketDetail);
            String userInfo = client.getHandshakeData().getHttpHeaders().get("User-Name");
            log.info("User info: {}", userInfo);
            // Access user information added after authorization
            log.info(client.getHandshakeData().getHttpHeaders().get("User"));
            // Add your business logic here.
            ackRequest.sendAckData("Demo event received");
        }
    };
    
  3. And we are done with our authentication of socket connection and it's time for a show case now.

Testing WebSocket Authentication

  1. Add the required headers based on your configuration and connect to the WebSocket server.

    Image showing how to pass headers in a WebSocket request through Postmand

  2. Now, if we hit the same event again that we created earlier, i.e, demoEvent, we will see a log message that it is able to pickup the username that we provided in the User-Name request header.

Conclusion

Congratulations! You've successfully set up WebSocket communication with Socker.IO in your Spring Boot application. You've learned how to configure WebSocket settings, create and handle events and implementation basic authentication for your WebSocket connections.
I hope it was helpful for everyone reading this!! If you have any queries, feel free to drop them down in the comments or reach me out.

Thanks a lot for reading this!!

springsecurity Article's
30 articles in total
Favicon
Understanding Spring Security and OAuth 2.0
Favicon
Spring Oauth2 - App-Token based Hybrid Token Verification Methods
Favicon
App-Token based easy OAuth2 implementation built to grow with Spring Boot
Favicon
Apache wicket with spring boot example application: notice board
Favicon
Spring Security: CSRF protection
Favicon
Mastering End-to-End Transactional Functionality in Spring Boot with Examples
Favicon
Spring Security: Redirect to login page if access pages which is for authorized user only
Favicon
Understanding the Spring Security Architecture
Favicon
Spring security
Favicon
Implementing Token-Based Authentication in Spring Boot Using Spring Security, JWT, and JDBC Template
Favicon
Implementing One-Time Token Authentication with Spring Security
Favicon
Login system with JWT token and email reset password
Favicon
Keycloak and Spring Boot: The Ultimate Guide to Implementing Single Sign-On
Favicon
Securing Your Spring Boot Application with Spring Security
Favicon
Guia básico de Spring Security
Favicon
OAuth2.0 Spring Boot
Favicon
Spring Boot Caching Simplified: How to Use JetCache Effectively
Favicon
OAuth 2 Token Exchange with Spring Security and Keycloak
Favicon
Implementing Spring Security in Microservices Architecture: A Deep Dive
Favicon
Mastering Spring Security: A Comedy of Errors (and Authentication)
Favicon
Spring Security For Beginners — Part 2
Favicon
Spring Boot with VueJS with Spring Security
Favicon
Spring Security: Protecting Your App from Everyone (Including You!)
Favicon
What is the CORS ?
Favicon
Spring Security For Beginners — Part 1
Favicon
Spring Boot WebSockets: Socket.io + Authentication + Postman
Favicon
Roadmap to Mastering the Spring Framework 🚀
Favicon
Spring Security 103: Exploring Default Security Configuration
Favicon
Spring Security 102: From Setup to Secure Endpoints in Spring Boot
Favicon
Spring Security 101: Understanding the Basics

Featured ones: