对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

Tokens认证

Spring Security OAuth 提供了基于Tokens的安全性支持,包括 JSON Web Token(JWT)。 您可以将其用作 Web 应用程序中的身份验证机制, 包括上一节所述的 WebSocket 上的 STOMP 通信(即通过基于 Cookie 的会话来维持身份)。spring-doc.cadn.net.cn

同时,基于 Cookie 的会话并不总是最合适的选择(例如,在不维护服务器端会话的应用程序中,或在通常使用请求头进行身份验证的移动应用程序中)。spring-doc.cadn.net.cn

WebSocket 协议(RFC 6455)“并未规定服务器在 WebSocket 握手过程中认证客户端的任何特定方式。”然而在实践中,浏览器客户端只能使用标准的认证头(即基本 HTTP 认证)或 Cookie,而无法(例如)提供自定义头信息。同样地,SockJS JavaScript 客户端也没有提供在 SockJS 传输请求中发送 HTTP 头的方法。参见 sockjs-client 问题 196。 取而代之的是,它允许发送查询参数,你可以利用该机制传递Tokens(token),但这也有其自身的缺点(例如,该Tokens可能会随 URL 被意外记录到服务器日志中)。spring-doc.cadn.net.cn

上述限制仅适用于基于浏览器的客户端,不适用于 Spring 的 Java STOMP 客户端,后者支持在 WebSocket 和 SockJS 请求中发送头部信息。

因此,希望避免使用 Cookie 的应用程序在 HTTP 协议层面可能没有其他好的身份验证替代方案。它们可以改为在 STOMP 消息协议层面通过请求头进行身份验证。这样做只需两个简单步骤:spring-doc.cadn.net.cn

  1. 在连接时使用 STOMP 客户端传递身份验证头信息。spring-doc.cadn.net.cn

  2. 使用 ChannelInterceptor 处理身份验证头信息。spring-doc.cadn.net.cn

下一个示例使用服务器端配置来注册一个自定义的身份验证拦截器。请注意,拦截器只需对 CONNECT Message 进行身份验证并设置用户头信息即可。Spring 会记录并保存已认证的用户,并将其与同一会话中的后续 STOMP 消息关联起来。以下示例展示了如何注册一个自定义的身份验证拦截器:spring-doc.cadn.net.cn

@Configuration
@EnableWebSocketMessageBroker
public class MyConfig 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())) {
					Authentication user = ... ; // access authentication header(s)
					accessor.setUser(user);
				}
				return message;
			}
		});
	}
}

此外,请注意,当你使用 Spring Security 对消息进行授权时,目前需要确保认证的 ChannelInterceptor 配置排在 Spring Security 的配置之前。最佳做法是将自定义拦截器声明在它自己的 WebSocketMessageBrokerConfigurer 实现类中,并使用 @Order(Ordered.HIGHEST_PRECEDENCE + 99) 注解进行标记。spring-doc.cadn.net.cn