#Real time Notifications with Springboot

12 messages · Page 1 of 1 (latest)

candid tiger
#

I am trying to build a Order Management System with real time update on ordered product status for both buyer and seller, in other words when buyer updates the order status seller should receive notification in real time.

This is first time i do something with websockets so i have been struggling with setting up the logic.

In my app i have authentication and authorization with jwt token and roles.

this is my configs:

eager mulchBOT
#

This post has been reserved for your question.

Hey @candid tiger! Please use /close or the Close Post button above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically closed after 300 minutes of inactivity.

TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.

candid tiger
#
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .csrf()
                .disable()
                .authorizeHttpRequests((requests) -> requests
                        .requestMatchers(
                                "/api/register/**",
                                "/api/register",
                                "chat/**",
                                "/chat/**"
                        )
                        .permitAll()
                        .requestMatchers("/api/public/**").permitAll()
                        .requestMatchers("/api/admin/**").hasRole(ADMIN.name())
                        .requestMatchers("/api/seller/**").hasAnyRole(Role.SELLER.name(), Role.ADMIN.name())
                        .requestMatchers("/api/buyer/**").hasAnyRole(Role.BUYER.name(), ADMIN.name())
                        .anyRequest().authenticated()
                )
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authenticationProvider(authenticationProvider)
                .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
}```
#
@Override
  protected void doFilterInternal(
          @NonNull HttpServletRequest request,
          @NonNull HttpServletResponse response,
          @NonNull FilterChain filterChain
  ) throws ServletException, IOException {

    if (request.getServletPath().contains("/api/register")) {
      logger.info("Skipping authentication for /api/register");
      filterChain.doFilter(request, response);
      return;
    }
    String authHeader="";
    if(request.getServletPath().contains("chat")){
      authHeader="Bearer "+request.getQueryString();

      var temp=request.getHeaderNames();
      logger.info(temp.toString());
    }
    else {
      authHeader = request.getHeader("Authorization");
    }
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
      logger.warn("Missing or invalid Authorization header");
      response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
      return;
    }
    final String jwt = authHeader.substring(7);
    var userId = jwtService.extractUserId(jwt);
    if (userId == null) {
      logger.warn("Could not extract user ID from JWT");
      response.setStatus(HttpServletResponse.SC_FORBIDDEN);
      return;
    }
    try {
      UserDetails userDetails = this.customUserDetailsService.loadUserById(UUID.fromString(userId));
      boolean isTokenValid = tokenRepository.findByToken(jwt)
              .map(t -> !t.isExpired() && !t.isRevoked())
              .orElse(false);



#
      if (jwtService.isTokenValid(jwt, userDetails) && isTokenValid) {
        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                userDetails, jwt, userDetails.getAuthorities()
        );
        authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        SecurityContextHolder.getContext().setAuthentication(authToken);
        logger.info("Authentication successful for user: "+ userId);
      } else {
        if (!jwtService.isTokenValid(jwt, userDetails)) {
          logger.warn("Invalid JWT token");
          response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        } else {
          logger.warn("Token is not valid in repository");
          response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        }
        return;
      }
      filterChain.doFilter(request, response);
    } catch (Exception e) {
      logger.error("Error in filter chain", e);
      response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    }
    logger.info("Response Status: {}", response.getStatus());
  }
}```
#

So in postman i can currently connect and its working by connecting with link:
ws://localhost:8080/chat?eyJhbGciOiJIUzI1NiJ9.e....(my token)

#

however i am not receiving or sending any messages.

In my code i created simple message that would be triggered after creating a product just to test the concept but its not sending anything:

@Controller
public class ChatController {

    private final SimpMessagingTemplate messagingTemplate;

    @Autowired
    public ChatController(SimpMessagingTemplate messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }

    @MessageMapping("/sendHi")
    @SendTo("/topic/messages")
    public OutputMessage sendHiMessage() {
        String time = new SimpleDateFormat("HH:mm").format(new Date());
        Message message = new Message("Saeed", "Hi");
        return new OutputMessage(message.getFrom(), message.getText(), time);
    }
}```

i call it from other controllers as follows:
```java
chatController.sendHiMessage();
#

this is my websocket confic file:


@Order(Ordered.HIGHEST_PRECEDENCE + 99)
@Configuration
@EnableWebSocketMessageBroker
@RequiredArgsConstructor
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {



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

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

}
#

I may be completely on the wrong side of things when it comes for real time notification

#

If you can spot my mistake or direct me to the right approach i would really appreciate it