- Configuration du projet et dépendances Maven
Pour commencer, créez un projet Spring Boot et ajoutez les dépendances suivantes à votre fichier pom.xml. Celles-ci incluent le support pour WebSocket, les bibliothèques côté client (SockJS, STOMP, jQuery) et Spring Security pour l'authentification.
<!-- Dépendance pour WebSocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- Locateur de ressources WebJars -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
</dependency>
<!-- Client SockJS pour la compatibilité navigateur -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>sockjs-client</artifactId>
<version>1.1.2</version>
</dependency>
<!-- Client STOMP pour la messagerie -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>stomp-websocket</artifactId>
<version>2.3.3</version>
</dependency>
<!-- Bibliothèque jQuery -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
<!-- Sécurité avec Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- Sécurisation de l'application avec Spring Security
Nous allons configurer Spring Security pour créer deux utilisateurs en mémoire : alice et bob, tous deux avec le mot de passe password. L'utilisateur alice aura les rôles ADMIN et USER, tandis que bob aura uniquement le rôle USER. Cela nous permettra de tester l'envoi de messages entre utilisateurs authentifiés.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecuriteWebSocketConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Mot de passe "password" encodé avec BCrypt
String encodedPassword = passwordEncoder().encode("password");
auth.inMemoryAuthentication()
.withUser("alice").password(encodedPassword).roles("ADMIN", "USER")
.and()
.withUser("bob").password(encodedPassword).roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
}
- Configuration du broker de messages WebSocket
Cette configuration active le broker de messages STOMP et définit un point de terminaison (endpoint) pour les connexions client. Nous configurons également un broker simple qui gérera les destinations préfixées par /topic (pour la diffusion) et /queue (pour les messages point-à-point).
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
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 registerStompEndpoints(StompEndpointRegistry registry) {
// Enregistre un endpoint "/ws-chat" et active SockJS pour la compatibilité
registry.addEndpoint("/ws-chat").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// Active un broker simple pour les destinations "/topic" et "/queue"
registry.enableSimpleBroker("/topic", "/queue");
// Définit le préfixe pour les messages destinés aux contrôleurs de l'application
registry.setApplicationDestinationPrefixes("/app");
}
}
- Création du contrôleur de messagerie
Le contrôleur reçoit les messages des clients via le préfixe /app. Il utilise SimpMessagingTemplate pour transférer le message à l'utilisateur de destination spécifié. Le préfixe /user est utilisé par Spring pour router le message vers la session de l'utilisateur cible.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import java.security.Principal;
@Controller
public class MessageController {
@Autowired
private SimpMessagingTemplate brokerMessaging;
@MessageMapping("/envoyerMessagePrive")
public void gererEnvoiMessage(Principal user, MessagePrive message) {
String expediteur = user.getName();
message.setExpediteur(expediteur);
// Envoie le message à un destinataire spécifique sur sa queue personnelle
brokerMessaging.convertAndSendToUser(
message.getDestinataire(),
"/queue/messages-prives",
message
);
}
}
class MessagePrive {
private String destinataire;
private String expediteur;
private String corps;
// Getters et Setters
public String getDestinataire() { return destinataire; }
public void setDestinataire(String destinataire) { this.destinataire = destinataire; }
public String getExpediteur() { return expediteur; }
public void setExpediteur(String expediteur) { this.expediteur = expediteur; }
public String getCorps() { return corps; }
public void setCorps(String corps) { this.corps = corps; }
}
- Développement de l'interface client
Créez une page HTML et un fichier JavaScript dans le dossier src/main/resources/static. La page chat.html contiendra l'interface utilisateur, et app.js gérera la connexion WebSocket et l'envoi/réception des messages.
chat.html
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Messagerie Instantanée</title>
<script src="/webjars/jquery/jquery.min.js"></script>
<script src="/webjars/sockjs-client/sockjs.min.js"></script>
<script src="/webjars/stomp-websocket/stomp.min.js"></script>
<script src="/app.js"></script>
</head>
<body>
<div id="chatContainer">
<h3>Envoyer un message privé</h3>
<div id="messageArea"></div>
<div>
<input type="text" id="messageInput" placeholder="Votre message">
<input type="text" id="recipientInput" placeholder="Destinataire (ex: alice)">
<button id="sendButton">Envoyer</button>
</div>
</div>
</body>
</html>
app.js
let clientStomp = null;
function connecter() {
const socket = new SockJS('/ws-chat');
clientStomp = Stomp.over(socket);
clientStomp.connect({}, function (frame) {
console.log('Connecté : ' + frame);
// S'abonne à la queue personnelle pour recevoir les messages privés
clientStomp.subscribe('/user/queue/messages-prives', function (reponse) {
afficherMessage(JSON.parse(reponse.body));
});
});
}
function envoyerMessage() {
const messageTexte = $("#messageInput").val();
const destinataire = $("#recipientInput").val();
if (messageTexte && destinataire) {
clientStomp.send("/app/envoyerMessagePrive", {},
JSON.stringify({ 'corps': messageTexte, 'destinataire': destinataire })
);
$("#messageInput").val('');
}
}
function afficherMessage(message) {
$("#messageArea").append("<div><strong>" + message.expediteur + "</strong> : " + message.corps + "</div>");
}
$(function () {
connecter();
$("#sendButton").click(function () {
envoyerMessage();
});
});
- Procédure de test
Pour tester l'application, ouvrez deux fenêtres de navigateur différentes.
- Dans la première fenêtre, naviguez vers
http://localhost:8080/chat.html. Vous serez redirigé vers la page de login de Spring Security. Connectez-vous en tant qu'alice (mot de passe : password). - Dans la deuxième fenêtre, naviguez vers la même URL et connectez-vous en tant que bob (mot de passe : password).
- Pour qu'alice envoie un message à bob, elle saisit son message dans le champ "Votre messsage", écrit
bobdans le champ "Destinataire", et clique sur "Envoyer". - Le message devrait apparaître instantanément dans la fenêtre de navigateur de bob.