Token 驗證
Spring Security OAuth 提供基於 Token 安全性的支援,包含 JSON Web Token (JWT)。您可以在 Web 應用程式中使用它作為驗證機制,包含 WebSocket 互動上的 STOMP,如前一節所述(也就是,透過基於 Cookie 的 Session 維護身分)。
同時,基於 Cookie 的 Session 並非總是最佳選擇(例如,在不維護伺服器端 Session 的應用程式中,或是在行動應用程式中,通常使用 Header 進行驗證)。
WebSocket 協定 RFC 6455 「未規定伺服器可以在 WebSocket 握手期間驗證用戶端的任何特定方式」。然而,實際上,瀏覽器用戶端只能使用標準驗證 Header(也就是基本 HTTP 驗證)或 Cookie,而不能(例如)提供自訂 Header。同樣地,SockJS JavaScript 用戶端不提供透過 SockJS 傳輸請求傳送 HTTP Header 的方式。請參閱 sockjs-client issue 196。相反地,它允許傳送查詢參數,您可以使用這些參數傳送 Token,但這有其自身的缺點(例如,Token 可能會不小心與伺服器記錄中的 URL 一起記錄)。
上述限制適用於基於瀏覽器的用戶端,但不適用於基於 Spring Java 的 STOMP 用戶端,後者確實支援透過 WebSocket 和 SockJS 請求傳送 Header。 |
因此,希望避免使用 Cookie 的應用程式可能在 HTTP 協定層級沒有任何好的驗證替代方案。他們可能更喜歡在 STOMP 訊息協定層級使用 Header 進行驗證,而不是使用 Cookie。這樣做需要兩個簡單步驟
-
在連線時使用 STOMP 用戶端傳遞驗證 Header。
-
使用
ChannelInterceptor
處理驗證 Header。
下一個範例使用伺服器端組態來註冊自訂驗證攔截器。請注意,攔截器只需要驗證並在 CONNECT Message
上設定使用者 Header。Spring 會記錄並儲存已驗證的使用者,並將其與同一 Session 上的後續 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)
。