令牌認證
Spring Security OAuth 提供了基於令牌的安全支援,包括 JSON Web Token (JWT)。您可以將其用作 Web 應用程式中的身份驗證機制,包括 WebSocket 上的 STOMP 互動,如上一節所述(即,透過基於 Cookie 的會話維護身份)。
同時,基於 Cookie 的會話並不總是最合適的(例如,在不維護伺服器端會話的應用程式中,或在移動應用程式中,通常使用標頭進行身份驗證)。
WebSocket 協議,RFC 6455“沒有規定伺服器在 WebSocket 握手期間對客戶端進行身份驗證的任何特定方式”。然而,在實踐中,瀏覽器客戶端只能使用標準身份驗證標頭(即,基本的 HTTP 身份驗證)或 Cookie,而不能(例如)提供自定義標頭。同樣,SockJS JavaScript 客戶端不提供傳送帶有 SockJS 傳輸請求的 HTTP 標頭的方式。請參閱 sockjs-client 問題 196。相反,它允許傳送可用於傳送令牌的查詢引數,但這有其自身的缺點(例如,令牌可能會無意中隨 URL 一起記錄在伺服器日誌中)。
| 上述限制適用於基於瀏覽器的客戶端,不適用於基於 Spring Java 的 STOMP 客戶端,該客戶端確實支援傳送帶有 WebSocket 和 SockJS 請求的標頭。 |
因此,希望避免使用 Cookie 的應用程式可能無法在 HTTP 協議級別找到任何好的身份驗證替代方案。它們可能更喜歡在 STOMP 訊息協議級別使用標頭進行身份驗證,而不是使用 Cookie。這樣做需要兩個簡單的步驟
-
使用 STOMP 客戶端在連線時傳遞身份驗證標頭。
-
使用
ChannelInterceptor處理身份驗證標頭。
下一個示例使用伺服器端配置來註冊自定義身份驗證攔截器。請注意,攔截器只需要在 CONNECT Message 上進行身份驗證並設定使用者標頭。Spring 會記錄並儲存已認證的使用者,並將其與同一會話上的後續 STOMP 訊息關聯。以下示例展示瞭如何註冊自定義身份驗證攔截器
-
Java
-
Kotlin
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if (StompCommand.CONNECT.equals(accessor.getCommand())) {
// Access authentication header(s) and invoke accessor.setUser(user)
}
return message;
}
});
}
}
@Configuration
@EnableWebSocketMessageBroker
class WebSocketConfiguration : WebSocketMessageBrokerConfigurer {
override fun configureClientInboundChannel(registration: ChannelRegistration) {
registration.interceptors(object : ChannelInterceptor {
override fun preSend(message: Message<*>, channel: MessageChannel): Message<*> {
val accessor = MessageHeaderAccessor.getAccessor(message,
StompHeaderAccessor::class.java)
if (StompCommand.CONNECT == accessor!!.command) {
// Access authentication header(s) and invoke accessor.setUser(user)
}
return message
}
})
}
}
此外,請注意,當您對訊息使用 Spring Security 的授權時,目前,您需要確保身份驗證 ChannelInterceptor 配置在 Spring Security 之前執行。最好透過在自己的 WebSocketMessageBrokerConfigurer 實現中宣告自定義攔截器來完成此操作,該實現標記為 @Order(Ordered.HIGHEST_PRECEDENCE + 99)。