Spring WebFlux身份验证的WebSocket连接

问题描述 投票:1回答:1

我运行的Spring [email protected]服务器具有公开的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 AuthenticationBearer Authenticationaccess_token查询参数实现用于建立WS连接的身份验证?

最好的选择是避免使用Spring Security。

谢谢。

spring-boot spring-webflux spring-websocket
1个回答
1
投票

Websocket连接从作为Upgraded的HTTP请求开始。您可以在升级之前执行JWT令牌认证。在春季启动中,它的工作方式如下:

公开自定义WebSocketService bean:

@Bean
public WebSocketService webSocketService(RequestUpgradeStrategy upgradeStrategy) {
        return new HandshakeWebSocketService(upgradeStrategy);
}

在您自己的类中实现RequestUpgradeStrategy接口:

@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);
                                              });
}

注意:

  • 以上类基于ReactorNettyRequestUpgradeStrategy

  • 返回reactorResponse.sendWebsocket是将连接升级到WebSocket连接的现有行为

  • 可以返回
  • reactorResponse.status以停止升级连接。例如,如果连接未经授权,您可以返回401响应。

  • 查询参数和Authentication标头可在握手信息中找到。如何进行身份验证本身不在问题范围内。

© www.soinside.com 2019 - 2024. All rights reserved.