令牌认证

Spring Security OAuth 提供了对基于令牌的安全性的支持,包括 JSON Web Token (JWT)。你可以将其用作 Web 应用程序(包括 STOMP over WebSocket 交互)中的认证机制,如上一节所述(即通过基于 cookie 的会话维护身份)。

同时,基于 cookie 的会话并非总是最佳选择(例如,在不维护服务器端会话的应用程序中,或在移动应用程序中,通常使用标头进行认证)。

WebSocket 协议,RFC 6455 “没有规定服务器在 WebSocket 握手期间认证客户端的任何特定方式。”然而,在实践中,浏览器客户端只能使用标准认证标头(即基本的 HTTP 认证)或 cookie,而不能(例如)提供自定义标头。同样,SockJS JavaScript 客户端不提供通过 SockJS 传输请求发送 HTTP 标头的方式。请参阅 sockjs-client issue 196。相反,它允许发送查询参数,你可以用它来发送令牌,但这有其自身的缺点(例如,令牌可能会无意中与 URL 一起记录在服务器日志中)。

上述限制适用于基于浏览器的客户端,不适用于 Spring 基于 Java 的 STOMP 客户端,后者支持通过 WebSocket 和 SockJS 请求发送标头。

因此,希望避免使用 cookie 的应用程序可能在 HTTP 协议级别上没有好的替代认证方式。它们可能更喜欢在 STOMP 消息协议级别上使用标头进行认证,而不是使用 cookie。这样做需要两个简单的步骤:

  1. 使用 STOMP 客户端在连接时传递认证标头。

  2. 使用 ChannelInterceptor 处理认证标头。

下一个示例使用服务器端配置来注册自定义认证拦截器。请注意,拦截器只需要认证并在 CONNECT Message 上设置用户标头。Spring 会记录并保存已认证的用户,并将其与同一会话上的后续 STOMP 消息关联。以下示例展示了如何注册自定义认证拦截器:

此外,请注意,当你使用 Spring Security 的消息授权时,目前你需要确保认证 ChannelInterceptor 配置的顺序在 Spring Security 之前。最好通过在其自己的 WebSocketMessageBrokerConfigurer 实现中声明自定义拦截器来完成此操作,该实现使用 @Order(Ordered.HIGHEST_PRECEDENCE + 99) 进行标记。