You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3纯WebSocket的OAuth安全验证实现方案问询

纯WebSocket(非STOMP)的OAuth2安全实现方案

核心思路:在握手阶段完成OAuth2令牌验证

WebSocket连接建立依赖HTTP握手升级流程,所以OAuth2验证必须在握手发起时完成——只有令牌合法的请求,才能升级为WebSocket连接。@EnableWebSocketSecurity确实只适配STOMP+Broker的消息场景,纯WebSocket需要自定义握手拦截逻辑来实现安全校验。

具体实现步骤

1. 自定义WebSocket握手拦截器

实现HandshakeInterceptor接口,在beforeHandshake方法中提取请求里的OAuth2令牌,调用授权服务器的令牌 introspect 接口验证有效性,验证通过才允许握手继续。

示例代码:

@Component
public class OAuth2WebSocketHandshakeInterceptor implements HandshakeInterceptor {

    private final OAuth2TokenIntrospector tokenIntrospector;

    public OAuth2WebSocketHandshakeInterceptor(OAuth2TokenIntrospector tokenIntrospector) {
        this.tokenIntrospector = tokenIntrospector;
    }

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        // 从请求头提取Bearer令牌
        String token = extractBearerToken(request.getHeaders());
        if (token == null) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return false;
        }

        try {
            // 调用授权服务器验证令牌
            OAuth2AuthenticatedPrincipal principal = tokenIntrospector.introspect(token);
            // 将用户信息存入会话属性,后续处理器可直接使用
            attributes.put("authenticatedUser", principal);
            return true;
        } catch (OAuth2AuthenticationException e) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return false;
        }
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
        // 握手完成后的收尾操作(可选)
    }

    private String extractBearerToken(HttpHeaders headers) {
        String authHeader = headers.getFirst(HttpHeaders.AUTHORIZATION);
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            return authHeader.substring(7);
        }
        return null;
    }
}

2. 绑定拦截器到WebSocket配置

在@EnableWebSocket的配置类中,注册WebSocket处理器时添加上述拦截器:

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    private final OAuth2WebSocketHandshakeInterceptor handshakeInterceptor;
    private final CustomWebSocketHandler webSocketHandler;

    public WebSocketConfig(OAuth2WebSocketHandshakeInterceptor handshakeInterceptor, CustomWebSocketHandler webSocketHandler) {
        this.handshakeInterceptor = handshakeInterceptor;
        this.webSocketHandler = webSocketHandler;
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketHandler, "/ws/connect")
                .addInterceptors(handshakeInterceptor)
                // 按需配置跨域规则
                .setAllowedOrigins("https://your-frontend-domain.com");
    }
}

3. 配置OAuth2令牌校验器

使用Spring提供的NimbusOAuth2TokenIntrospector对接授权服务器的令牌 introspect 端点:

@Configuration
public class OAuth2ResourceServerConfig {

    @Value("${spring.security.oauth2.resourceserver.introspection-uri}")
    private String introspectUri;

    @Value("${spring.security.oauth2.resourceserver.client-id}")
    private String clientId;

    @Value("${spring.security.oauth2.resourceserver.client-secret}")
    private String clientSecret;

    @Bean
    public OAuth2TokenIntrospector tokenIntrospector() {
        NimbusOAuth2TokenIntrospector introspector = new NimbusOAuth2TokenIntrospector(introspectUri);
        introspector.setClientCredentials(clientId, clientSecret);
        return introspector;
    }
}

4. 在WebSocket处理器中获取用户信息

握手通过后,用户认证信息会存在WebSocket会话的属性中,处理器可直接取用:

@Component
public class CustomWebSocketHandler extends TextWebSocketHandler {

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        OAuth2AuthenticatedPrincipal user = (OAuth2AuthenticatedPrincipal) session.getAttributes().get("authenticatedUser");
        String username = user.getName();
        // 业务逻辑处理
        session.sendMessage(new TextMessage("已收到消息,当前用户:" + username));
    }
}

关键问题解答

  • 是否需要实现拦截器? 是的,这是纯WebSocket场景下OAuth2验证的唯一可行方式——通过拦截握手请求完成令牌校验,阻止非法连接建立。
  • 是否要在握手阶段执行验证? 必须在握手阶段做。因为WebSocket连接建立后,后续消息传输脱离HTTP上下文,无法再通过Spring Security过滤器链拦截,所以身份验证只能在握手升级前完成。
  • @EnableWebSocketSecurity为什么不适用? 该注解是专为STOMP+Broker模式设计的,它依赖消息代理的消息拦截机制,纯WebSocket没有Broker支撑,因此无法生效。

内容的提问来源于stack exchange,提问作者HereAndBeyond

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 20:53:18