Spring WebSocket安全認證與權限控制解析

一、認證架構設計

1.1 WebSocket安全認證流程

客戶端服務端HTTP握手請求(攜帶Token)認證攔截器校驗Token101 Switching ProtocolsWebSocket通信401 Unauthorizedalt[認證成功][認證失敗]客戶端服務端

1.2 安全組件矩陣

組件職責關鍵技術點
HandshakeInterceptor握手前認證Token解析/校驗
ChannelInterceptor消息級鑒權@PreAuthorize
SimpUserRegistry用戶會話管理Principal關聯
SecurityContext安全上下文線程局部變量

二、生產級認證實現

2.1 JWT認證攔截器

public class JwtHandshakeInterceptor implements HandshakeInterceptor {private final JwtDecoder jwtDecoder;@Overridepublic boolean beforeHandshake(ServerHttpRequest request,ServerHttpResponse response,WebSocketHandler wsHandler,Map<String, Object> attributes) throws Exception {String token = extractToken(request);if (token == null) {response.setStatusCode(HttpStatus.UNAUTHORIZED);return false;}try {Jwt jwt = jwtDecoder.decode(token);attributes.put("jwt", jwt);return true;} catch (JwtException e) {response.setStatusCode(HttpStatus.FORBIDDEN);return false;}}private String extractToken(ServerHttpRequest request) {// 從Header/QueryParam/Cookie中提取TokenList<String> headers = request.getHeaders().get("Authorization");if (headers != null && !headers.isEmpty()) {String header = headers.get(0);if (header.startsWith("Bearer ")) {return header.substring(7);}}return null;}@Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,WebSocketHandler wsHandler, Exception exception) {// 握手后處理邏輯}
}

2.2 消息級權限控制

@Configuration
@EnableWebSocketSecurity
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {@Overrideprotected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {messages.simpDestMatchers("/app/device/**").hasRole("DEVICE").simpSubscribeDestMatchers("/topic/admin/**").hasRole("ADMIN").simpSubscribeDestMatchers("/user/queue/**").authenticated().anyMessage().denyAll();}@Overrideprotected boolean sameOriginDisabled() {return true; // 禁用CSRF保護(根據需求配置)}@Beanpublic ChannelInterceptor authorizationChannelInterceptor() {return new ChannelInterceptor() {@Overridepublic Message<?> preSend(Message<?> message, MessageChannel channel) {StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);if (StompCommand.CONNECT.equals(accessor.getCommand())) {Authentication auth = (Authentication) accessor.getHeader("simpUser");if (auth == null || !auth.isAuthenticated()) {throw new AuthenticationCredentialsNotFoundException("未認證");}}return message;}};}
}

三、高級安全特性

3.1 雙因素認證集成

public class TwoFactorAuthInterceptor implements ChannelInterceptor {@Overridepublic Message<?> preSend(Message<?> message, MessageChannel channel) {StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);if (StompCommand.SUBSCRIBE.equals(accessor.getCommand())) {Principal principal = accessor.getUser();String sessionId = accessor.getSessionId();if (isSensitiveDestination(accessor.getDestination()) &&!twoFactorService.isVerified(principal.getName(), sessionId)) {throw new TwoFactorRequiredException("需要二次認證");}}return message;}private boolean isSensitiveDestination(String destination) {return destination != null &&(destination.startsWith("/topic/finance") ||destination.startsWith("/app/admin"));}
}

3.2 速率限制控制

@Bean
public ChannelInterceptor rateLimitingInterceptor() {return new ChannelInterceptor() {private final RateLimiter limiter = RateLimiter.create(100); // 100條/秒@Overridepublic Message<?> preSend(Message<?> message, MessageChannel channel) {if (!limiter.tryAcquire()) {throw new RateLimitExceededException("消息發送頻率過高");}return message;}};
}

四、集群環境方案

4.1 分布式會話管理

@Configuration
@EnableRedisHttpSession
public class SessionConfig {@Beanpublic RedisMessageListenerContainer redisContainer(RedisConnectionFactory factory,SessionExpiredListener listener) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(factory);container.addMessageListener(listener,new PatternTopic("__keyevent@*__:expired"));return container;}@Componentpublic static class SessionExpiredListener implements MessageListener {@Autowiredprivate SimpUserRegistry userRegistry;@Overridepublic void onMessage(Message message, byte[] pattern) {String key = new String(message.getBody());if (key.startsWith("spring:session:sessions:")) {String sessionId = key.substring(25);userRegistry.users().stream().filter(user -> user.getSession(sessionId) != null).findFirst().ifPresent(user -> {SimpUser simpUser = userRegistry.getUser(user.getName());simpUser.getSession(sessionId).close(CloseStatus.SESSION_NOT_RELIABLE);});}}}
}

4.2 跨節點消息審計

@Configuration
public class AuditConfig {@Beanpublic MessageChannel auditChannel() {return new ExecutorSubscribableChannel(taskExecutor());}@Beanpublic ThreadPoolTaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(1000);return executor;}@Bean@ServiceActivator(inputChannel = "auditChannel")public MessageHandler auditHandler() {return message -> {StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);String user = Optional.ofNullable(accessor.getUser()).map(Principal::getName).orElse("anonymous");auditService.log(user,accessor.getSessionId(),accessor.getCommand().name(),accessor.getDestination(),Instant.now());};}
}

五、監控與運維

5.1 健康檢查端點

@RestController
@RequestMapping("/actuator/websocket")
public class WebSocketMetricsEndpoint {@Autowiredprivate SimpUserRegistry userRegistry;@GetMapping("/connections")public Map<String, Object> connectionMetrics() {Map<String, Object> metrics = new LinkedHashMap<>();metrics.put("activeConnections", userRegistry.getUserCount());metrics.put("activeSessions", userRegistry.users().stream().mapToInt(u -> u.getSessions().size()).sum());return metrics;}@GetMapping("/users")public Collection<SimpUser> activeUsers() {return userRegistry.users();}
}

5.2 異常處理策略

@ControllerAdvice
public class WebSocketExceptionHandler {@MessageExceptionHandler@SendToUser("/queue/errors")public ErrorResponse handleException(Exception ex) {ErrorResponse response = new ErrorResponse();response.setTimestamp(Instant.now());if (ex instanceof AuthenticationException) {response.setCode("AUTH_ERROR");response.setMessage("認證失敗");} else if (ex instanceof AccessDeniedException) {response.setCode("ACCESS_DENIED");response.setMessage("權限不足");} else {response.setCode("INTERNAL_ERROR");response.setMessage("服務器內部錯誤");}return response;}@Datapublic static class ErrorResponse {private String code;private String message;private Instant timestamp;}
}

六、前端安全集成

6.1 Token刷新機制

function connectWebSocket() {const socket = new SockJS('/ws');const stompClient = Stomp.over(socket);const headers = {'Authorization': `Bearer ${getAccessToken()}`};stompClient.connect(headers, () => {// 連接成功處理}, (error) => {if (error.headers?.message === 'TOKEN_EXPIRED') {refreshToken().then(newToken => {headers.Authorization = `Bearer ${newToken}`;connectWebSocket(); // 重連});}});
}

6.2 安全斷開處理

function setupWebSocket() {let reconnectAttempts = 0;const maxReconnectAttempts = 3;function connect() {stompClient.connect(headers, frame => {reconnectAttempts = 0;// 心跳檢測const heartbeatInterval = setInterval(() => {if (!stompClient.connected) {clearInterval(heartbeatInterval);return;}stompClient.send("/app/heartbeat");}, 30000);stompClient.onclose = () => {clearInterval(heartbeatInterval);if (reconnectAttempts < maxReconnectAttempts) {setTimeout(connect, 1000 * Math.pow(2, reconnectAttempts));reconnectAttempts++;}};});}window.addEventListener('beforeunload', () => {if (stompClient.connected) {stompClient.disconnect(() => {}, {});}});
}

通過以上方案,可以構建出企業級安全的WebSocket通信系統。建議在實際部署時:

  1. 根據業務需求調整認證粒度
  2. 實施完善的監控告警機制
  3. 定期進行安全審計
  4. 建立完整的證書管理體系
  5. 制定詳細的應急響應預案

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/92806.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/92806.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/92806.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

復現論文《多無人機協同任務分配算法設計與實現》

1. 論文標題 多無人機協同任務分配算法設計與實現 The Design and Implementation of Multi-UAVs Cooperative Task Assignment Algorithm 2. 內容概括 該論文針對異構多無人機協同執行多目標多類型任務時的分配問題展開研究。首先提出“兩階段”任務分配結構:第一階段通過…

MCU-基于TC397的啟動流程

TC397的啟動流程(Start Sequence) 整體啟動流程包括固件啟動(Boot Firmware)和 Bootloader 和軟件啟動(Application start-up software)三個階段。 1. Boot Firmware:是芯片上電后最開始執行的代碼,代碼由英飛凌供應商固化在BootRom中的,不可編程,沒辦法對BootRom中的…

單片機畢業設計模板|畢設答辯|畢業設計項目|畢設設計|單片機物聯網畢業設計|基于STM32單片機的紗管圖像識別系統設計

畢業設計題目&#xff1a;基于STM32單片機的紗管圖像識別系統設計1. 需求分析目標用戶&#xff1a;紡織行業&#xff0c;自動化生產線&#xff0c;質量檢測等。核心功能&#xff1a;實時識別和檢測紗管的外觀缺陷&#xff08;如破損、色差等&#xff09;。提供數據記錄和報告功…

谷歌DeepMind發布Genie 3:通用型世界模型,可生成前所未有多樣化的交互式虛擬環境

每周跟蹤AI熱點新聞動向和震撼發展 想要探索生成式人工智能的前沿進展嗎&#xff1f;訂閱我們的簡報&#xff0c;深入解析最新的技術突破、實際應用案例和未來的趨勢。與全球數同行一同&#xff0c;從行業內部的深度分析和實用指南中受益。不要錯過這個機會&#xff0c;成為AI領…

202506 電子學會青少年等級考試機器人二級理論綜合真題

更多內容和歷年真題請查看網站&#xff1a;【試卷中心 -----> 電子學會 ----> 機器人技術 ----> 二級】 網站鏈接 青少年軟件編程歷年真題模擬題實時更新 2025年6月 青少年等級考試機器人理論真題二級 第 1 題 如圖&#xff0c;這是中國古代發明的指南車模型&am…

【YOLO11改進 - C3k2融合】C3k2融合EBlock(Encoder Block):低光增強編碼器塊,利用傅里葉信息增強圖像的低光條件

YOLOv11目標檢測創新改進與實戰案例專欄 文章目錄&#xff1a; YOLOv11創新改進系列及項目實戰目錄 包含卷積&#xff0c;主干 注意力&#xff0c;檢測頭等創新機制 以及 各種目標檢測分割項目實戰案例 專欄鏈接: YOLOv11目標檢測創新改進與實戰案例 文章目錄YOLOv11目標檢測創…

MACBOOK M1安裝達夢8數據庫

前提已安裝好了docker 然后通過docker-compose安裝 version: 2.1 services:DM8:image: qinchz/dm8-arm64:8.1.8.128container_name: dm8ports:- "52330:5236"mem_limit: 2gmemswap_limit: 2genvironment:- TZAsia/Shanghai- LANGen_US.UTF-8volumes:- /Users/a1/dock…

2013年考研數學(二)真題

一、選擇題(1)考點&#xff1a;低階無窮小定義、高階無窮小定義、同階無窮小定義、等階無窮小定義、移項變形/極限存在并且分母→0時則分子也→0方法一&#xff1a;方法二&#xff1a;(2)考點&#xff1a;說不清楚的思路/湊導數定義式、洛必達法則、隱函數求導方法一&#xff1…

WinForm 復合控件(用戶控件):創建與使用指南

目錄 添加流程示意圖 復合控件的核心價值 與自定義控件的區別 創建步驟 建好的示例控件 ?使用方法&#xff08;代碼示例&#xff09; 設計原則 添加流程示意圖 點擊添加 添加成功 每更新一次復合控件的內容&#xff0c;就需要生成一次 ↓ 添加好復合控件后點這里更新一…

隨機向量正交投影定理(Orthogonal Projection Theorem, OPT)_學習筆記

前言 隨機向量正交投影定理&#xff08;Orthogonal Projection Theorem, OPT&#xff09; 是理解和推導卡爾曼了濾波&#xff08;Kalman Filtrering, KF&#xff09; 重要理論工具&#xff0c;簡化卡爾曼最優濾波方程推導過程并提供數學嚴密性。本文介紹該定理內容及證明過程&a…

11-netty基礎-手寫rpc-支持多序列化協議-03

netty系列文章&#xff1a; 01-netty基礎-socket02-netty基礎-java四種IO模型03-netty基礎-多路復用select、poll、epoll04-netty基礎-Reactor三種模型05-netty基礎-ByteBuf數據結構06-netty基礎-編碼解碼07-netty基礎-自定義編解碼器08-netty基礎-自定義序列化和反序列化09-n…

艾體寶產品 | 從“被看見”到“被信任”:GWI 協助洞察消費者,重構品牌認知

簡介&#xff1a;本文介紹了基于消費者洞察構建品牌認知策略的核心方法。通過深度理解受眾&#xff0c;GWI Spark 快速獲取真實洞察&#xff0c;指導信息與渠道選擇。GWI 幫助追蹤情感與認知效果&#xff0c;避免無效曝光陷阱&#xff0c;最終幫助品牌實現從“被看見”到“被信…

Redis高級

目錄 一、Redis主從 1. 主從集群結構 2. 主從同步原理 2.1 全量同步 2.2 增量同步 3. 主從同步優化 4. 總結 二、Redis哨兵 1. 哨兵工作原理 1.1 哨兵作用 1.2 狀態監控 1.3 選舉新的master節點 2. 總結 三、Redis分片集群 1. 散列插槽 2. 故障轉移 四、Redis…

正點原子esp32s3探測土壤濕度

開發板使用&#xff1a;正點原子ATK_DNESP32S3 V1.3 IDE: VSCODE PLATFORMIO 土壤濕度檢測傳感器模塊如下圖&#xff1a; 引腳&#xff1a; 傳感器VCC --> ESP32[3.3V] 傳感器GND --> ESP32[GND] 傳感器A0 --> ESP32[GPIO20] 代碼如下&#xff1a; #include <…

一篇文章解決 Win10 同時部署多個版本的Tomcat

文章目錄所用到的文件夾Tomcat服務端口修改Tomcat參數修改環境變量配置驗證環境是否配置成功可能遇到的問題問題一&#xff1a;startup.bat閃退問題二&#xff1a;startup.bat成功啟動&#xff0c;但仍打不開服務器總結最近在學習JavaWeb的時候&#xff0c;想安裝新版本的Tomca…

CentOS7安裝和使用Workbench

文章目錄CentOS7安裝和使用Workbench一、前言1.簡介2.環境二、正文1.更換鏡像源2.安裝依賴包3.下載4.安裝5.打開workbench6.使用記錄1&#xff09;連接數據庫2&#xff09;創建數據庫3&#xff09;導入數據3&#xff09;導出數據4&#xff09;運行SQL腳本5&#xff09;打開SQL腳…

SpringBoot查詢方式全解析

文章目錄一、簡介二、常用注解分類1、請求映射類&#xff08;處理 URL 與 HTTP 方法的綁定&#xff09;2、參數綁定類&#xff08;從請求中獲取數據并綁定到方法參數&#xff09;3、控制器與增強類&#xff08;標識控制器及全局增強&#xff09;4、異常與響應處理類&#xff08…

Linux操作系統從入門到實戰(十五)詳細講解Linux調試器 gdb/cgdb使用

Linux操作系統從入門到實戰&#xff08;十五&#xff09;詳細講解Linux調試器 gdb/cgdb使用前言一、gdb/cgdb是什么&#xff1f;1. 程序的兩種發布模式&#xff08;debug 和 release&#xff09;二、gdb/cgdb如何啟動&#xff1f;1. 準備工作2. 啟動 gdb/cgdb 調試器2.1 啟動 g…

基于UDP的代理協議的Tuic怎么樣?

Tuic&#xff08;全稱“TUIClient”&#xff09;是一款基于UDP協議的輕量代理工具&#xff0c;主打低延遲與高實時性&#xff0c;專為解決傳統TCP代理在實時場景中的性能瓶頸而生。其核心設計圍繞“UDP優先”展開&#xff0c;通過簡化握手流程、優化加密效率&#xff0c;在保持…

緩存投毒進階 -- justctf 2025 Busy Traffic

題目核心邏輯如下 let browser; // 全局瀏覽器實例// 訪問指定 URL 的異步函數 const visit async (url) > {try {// 如果已有瀏覽器實例&#xff0c;先關閉并等待 2 秒if (browser) {await browser.close();await sleep(2000);console.log("Terminated ongoing job.&…