使用Spring STOMP時ChannelInterceptor無法獲取用戶信息


Spring中websocket相關的Bean有一個專門的Scope——websocket,因此這在這些Bean當中是無法注入Scope為request的各種Bean的。這也挺正常的,一個websocket可能會持續很長時間,request的各種Bean僅僅在握手的時候有用,一直不釋放也不是個辦法。

STOMP中用戶身份認證主要來自於握手的Http請求,具體來說來源於方法DefaultHandshakeHandler#getUser()。各種Web的機制在這里也基本都適用。但當客戶端請求連接各種TOPIC,特別是各種動態的TOPIC時,鑒權的問題就有點不一樣了。Spring文檔中有這一句:

When a WebSocket handshake is made and a new WebSocket session is created, Spring’s WebSocket support automatically propagates the java.security.Principal from the HTTP request to the WebSocket session.

也就是說request中的Principal會自動轉到websocket中去,很好。然后我們可以利用ChannelInterceptor來攔截訂閱請求。但這時候發現,Principal居然是null

@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
    StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(message);
    if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand())) {
        Principal principal = headerAccessor.getUser();
        // principal is null here
    }
    return message;
}

原因倒是很簡單,SpringBoot的starter少了一個依賴:

compile 'org.springframework.security:spring-security-messaging'

缺少這個庫不會引發任何異常也沒有任何Log,但是會使得上面的代碼拿不到Principal。可以說各種AutoConfiguration還是挺容易留下這種坑的。SpringBoot的各種Starter用來很爽,就是很容易讓人知其然不知其所以然,太多的細節被隱藏了,如果程序工作得好倒還OK,一旦出現問題,連從哪里開始排查都不知道。像上面的情況,引入的相關的Starter,但是需要的特性還要格外的依賴,文檔中又沒有說明,是最容易踩到的大坑。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM