Spring WebFlux 认证的 WebSocket 连接
Spring WebFlux authenticated WebSocket connection
我有 运行 Spring Boot@2.2.x
服务器公开了 WebSocket 端点。这是我的 WebSocketConfiguration
:
@Slf4j
@Configuration
public class WebSocketConfiguration {
private static final String WS_PATH = "/ws/notifications";
@Bean
public HandlerMapping webSocketHandlerMapping() {
Map<String, WebSocketHandler> handlersMap = new HashMap<>();
handlersMap.put(WS_PATH, session -> session.send(session.receive()
.map(WebSocketMessage::getPayloadAsText)
.doOnEach(logNext(log::info))
.map(msg -> format("notification for your msg: %s", msg))
.map(session::textMessage)));
SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
handlerMapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
handlerMapping.setUrlMap(handlersMap);
return handlerMapping;
}
@Bean
public WebSocketHandlerAdapter handlerAdapter(WebSocketService webSocketService) {
return new WebSocketHandlerAdapter(webSocketService);
}
@Bean
public WebSocketService webSocketService() {
return new HandshakeWebSocketService(new ReactorNettyRequestUpgradeStrategy());
}
}
问题是如何使用 Basic Authentication
或 Bearer Authentication
或 access_token
查询参数实现建立 WS 连接的身份验证?
最好的选择是避免使用 Spring 安全。
谢谢。
Websocket 连接以 Upgraded
的 HTTP 请求开始。您可以在升级之前进行 JWT 令牌身份验证。在 spring 引导中,它的工作方式如下:
公开自定义 WebSocketService
bean:
@Bean
public WebSocketService webSocketService(RequestUpgradeStrategy upgradeStrategy) {
return new HandshakeWebSocketService(upgradeStrategy);
}
在你自己的class中实现RequestUpgradeStrategy
接口class:
@Override
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler, @Nullable String subProtocol, Supplier<HandshakeInfo> handshakeInfoFactory) {
ServerHttpResponse response = exchange.getResponse();
HttpServerResponse reactorResponse = getNativeResponse(response);
HandshakeInfo handshakeInfo = handshakeInfoFactory.get();
NettyDataBufferFactory bufferFactory = (NettyDataBufferFactory) response.bufferFactory();
var authResult = validateAuth(handshakeInfo);
if (authResult == unauthorised) return Mono.just(reactorResponse.status(rejectedStatus))
.flatMap(HttpServerResponse::send);
else return reactorResponse.sendWebsocket(subProtocol, //
this.maxFramePayloadLength,//
(in, out) -> {
ReactorNettyWebSocketSession session = new ReactorNettyWebSocketSession(in, out,
handshakeInfo,
bufferFactory,
this.maxFramePayloadLength);
return handler.handle(session);
});
}
备注:
以上class是基于ReactorNettyRequestUpgradeStrategy
。
返回reactorResponse.sendWebsocket
是将连接升级为WebSocket连接的现有行为
reactorResponse.status
可以 returned 来停止正在升级的连接。例如,在未授权连接的情况下,您可以 return 401
响应。
查询参数和Authentication
headers可以在握手信息中找到。如何进行身份验证本身不在问题范围内。
我有 运行 Spring Boot@2.2.x
服务器公开了 WebSocket 端点。这是我的 WebSocketConfiguration
:
@Slf4j
@Configuration
public class WebSocketConfiguration {
private static final String WS_PATH = "/ws/notifications";
@Bean
public HandlerMapping webSocketHandlerMapping() {
Map<String, WebSocketHandler> handlersMap = new HashMap<>();
handlersMap.put(WS_PATH, session -> session.send(session.receive()
.map(WebSocketMessage::getPayloadAsText)
.doOnEach(logNext(log::info))
.map(msg -> format("notification for your msg: %s", msg))
.map(session::textMessage)));
SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
handlerMapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
handlerMapping.setUrlMap(handlersMap);
return handlerMapping;
}
@Bean
public WebSocketHandlerAdapter handlerAdapter(WebSocketService webSocketService) {
return new WebSocketHandlerAdapter(webSocketService);
}
@Bean
public WebSocketService webSocketService() {
return new HandshakeWebSocketService(new ReactorNettyRequestUpgradeStrategy());
}
}
问题是如何使用 Basic Authentication
或 Bearer Authentication
或 access_token
查询参数实现建立 WS 连接的身份验证?
最好的选择是避免使用 Spring 安全。
谢谢。
Websocket 连接以 Upgraded
的 HTTP 请求开始。您可以在升级之前进行 JWT 令牌身份验证。在 spring 引导中,它的工作方式如下:
公开自定义 WebSocketService
bean:
@Bean
public WebSocketService webSocketService(RequestUpgradeStrategy upgradeStrategy) {
return new HandshakeWebSocketService(upgradeStrategy);
}
在你自己的class中实现RequestUpgradeStrategy
接口class:
@Override
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler, @Nullable String subProtocol, Supplier<HandshakeInfo> handshakeInfoFactory) {
ServerHttpResponse response = exchange.getResponse();
HttpServerResponse reactorResponse = getNativeResponse(response);
HandshakeInfo handshakeInfo = handshakeInfoFactory.get();
NettyDataBufferFactory bufferFactory = (NettyDataBufferFactory) response.bufferFactory();
var authResult = validateAuth(handshakeInfo);
if (authResult == unauthorised) return Mono.just(reactorResponse.status(rejectedStatus))
.flatMap(HttpServerResponse::send);
else return reactorResponse.sendWebsocket(subProtocol, //
this.maxFramePayloadLength,//
(in, out) -> {
ReactorNettyWebSocketSession session = new ReactorNettyWebSocketSession(in, out,
handshakeInfo,
bufferFactory,
this.maxFramePayloadLength);
return handler.handle(session);
});
}
备注:
以上class是基于
ReactorNettyRequestUpgradeStrategy
。返回
reactorResponse.sendWebsocket
是将连接升级为WebSocket连接的现有行为reactorResponse.status
可以 returned 来停止正在升级的连接。例如,在未授权连接的情况下,您可以 return401
响应。查询参数和
Authentication
headers可以在握手信息中找到。如何进行身份验证本身不在问题范围内。