Spring Boot + WebSocket + Spring Security(定向发送消息)

    科技2026-04-05  8

    定向发送消息涉及到用户,需要引入Spring Security相关内容。

    1.添加Spring Security,websocket和thymeleaf等依赖
    <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
    2.配置Spring Security
    @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception{ http.authorizeRequests() .antMatchers("/","/login").permitAll() //对"/"和/"login"路径不拦截 .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") //登录页面 .defaultSuccessUrl("/chat") //登录成功后跳转页面 .permitAll() .and() .logout() .permitAll(); } //内存中分配两个用户 /**inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())",这相当于登陆时用BCrypt加密方式对用户密码进行处理. *以前的".password("123")" 变成了 ".password(new BCryptPasswordEncoder().encode("123"))", *这相当于对内存中的密码进行Bcrypt编码加密.如果比对时一致,说明密码正确,才允许登陆.*/ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception{ auth.inMemoryAuthentication() .passwordEncoder(new BCryptPasswordEncoder()).withUser("user1").password(new BCryptPasswordEncoder().encode("123")).roles("USER") .and() .passwordEncoder(new BCryptPasswordEncoder()).withUser("user2").password(new BCryptPasswordEncoder().encode("123")).roles("USER"); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/resources/static/**"); //该目录下的静态资源不进行拦截 } }
    3.配置WebSocket
    @Configuration @EnableWebSocketMessageBroker//开启使用STOMP协议来传输基于代理(message broker)的消息 public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { //注册STOMP协议的节点(endPoint),并映射指定的URL @Override public void registerStompEndpoints(StompEndpointRegistry registry){ registry.addEndpoint("/endpointChat").withSockJS(); //注册一个名为/endpointChat的endpoint } //配置消息代理(Message Broker) @Override public void configureMessageBroker(MessageBrokerRegistry registry){ registry.enableSimpleBroker("queue", "/topic"); //点对点增加一个/queue消息代理 } }
    4.控制器
    @Controller public class WsController { @Autowired private SimpMessagingTemplate messagingTemplate; // 通过messagingTemplate向浏览器发送消息 @MessageMapping("/chat") public void handleChat(Principal principal, String msg){ //在spring MVC中,可以直接在参数中获得principal,principal中包含当前用户的信息 if(principal.getName().equals("user1")){ //如果当前用户是user1,则发给user2,反之亦然 messagingTemplate.convertAndSendToUser("user2", "/queue/notifications", principal.getName() + "-send:" + msg); //向用户发送消息,"/queue/notifications"是浏览器的订阅地址 }else { messagingTemplate.convertAndSendToUser("user1", "/queue/notifications", principal.getName() + "-send:" + msg); } } }
    5.登录页面和聊天页面

    登录页面

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"> <meta charset="UTF-8" /> <head> <title>登陆页面</title> </head> <body> <div th:if="${param.error}"> 无效的账号和密码 </div> <div th:if="${param.logout}"> 你已注销 </div> <form th:action="@{/login}" method="post"> <div><label> 账号 : <input type="text" name="username"/> </label></div> <div><label> 密码: <input type="password" name="password"/> </label></div> <div><input type="submit" value="登陆"/></div> </form> </body> </html>

    聊天页面

    <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <meta charset="UTF-8" /> <head> <title>Home</title> <script th:src="@{sockjs.min.js}"></script> <script th:src="@{stomp.min.js}"></script> <script th:src="@{jquery.js}"></script> </head> <body> <p> 聊天室 </p> <form id="messageForm"> <textarea rows="4" cols="60" name="text"></textarea> <input type="submit"/> </form> <script th:inline="javascript"> $('#messageForm').submit(function(e){ e.preventDefault(); var text = $('#messageForm').find('textarea[name="text"]').val(); sendSpittle(text); }); var sock = new SockJS("/endpointChat"); //连接endpoint名为"/endpointChat"的endpoint var stomp = Stomp.over(sock); stomp.connect('guest', 'guest', function(frame) { stomp.subscribe("/user/queue/notifications", handleNotification);//订阅"/user/queue/notifications"发送的消息,这里与控制器中定义的订阅地址保持一直。这里的"/user"是必须要的,使用了/user才会发送消息到指定的用户 }); function handleNotification(message) { $('#output').append("<b>Received: " + message.body + "</b><br/>") } function sendSpittle(text) { stomp.send("/chat", {}, text);//3 } $('#stop').click(function() {sock.close()}); </script> <div id="output"></div> </body> </html>
    6.配置WebMvcConfig
    @Configuration public class WebMvcConfigMy implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/login").setViewName("/login"); registry.addViewController("/chat").setViewName("/chat"); } }
    7.该页面需要的js

    链接: https://pan.baidu.com/s/1LC1JNdm-R9yU49GIGm4M1w 密码: l808

    Processed: 0.028, SQL: 9