使用 Stomp 在 Spring Boot 中访问 JWT 令牌

Posted

技术标签:

【中文标题】使用 Stomp 在 Spring Boot 中访问 JWT 令牌【英文标题】:Access JWT token in Spring Boot with Stomp 【发布时间】:2022-01-14 16:31:49 【问题描述】:

我已经按照this guide 设置了 ng2-stompjs,但是在我的 Spring 引导后端遇到问题,因为我使用的是 JWT 令牌。

首先,由于我的 JWT 安全性,stomp 服务不想连接,所以我将其添加到安全配置中:

安全配置:

http.authorizeRequests().antMatchers("/websockets").permitAll();

WebSocket配置

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) 
    registry.addEndpoint("/websockets").setAllowedOrigins("*");

我的前端 stomp 配置:

import  InjectableRxStompConfig  from '@stomp/ng2-stompjs';

export const myRxStompConfig: InjectableRxStompConfig = 
  // Which server?
  brokerURL: 'ws:/localhost:3000/websockets',

  // How often to heartbeat?
  // Interval in milliseconds, set to 0 to disable
  heartbeatIncoming: 0, // Typical value 0 - disabled
  heartbeatOutgoing: 20000, // Typical value 20000 - every 20 seconds

  // Wait in milliseconds before attempting auto reconnect
  // Set to 0 to disable
  // Typical value 500 (500 milli seconds)
  reconnectDelay: 200,

  // Will log diagnostics on console
  // It can be quite verbose, not recommended in production
  // Skip this key to stop logging to console
  debug: (msg: string): void => 
    console.log(new Date(), msg);
  ,

  beforeConnect: (stompClient: any): Promise<void> => 
    const token = localStorage.getItem('JWT_TOKEN');
    return new Promise<void>((resolve, _) => 
      stompClient.connectHeaders = 
        Authorization: 'Bearer ' + token, //also tried x-auth-token
      ;
      resolve();
    );
  ,
;

以及我使用套接字的组件(注意:如果目的地不正确,请忽略,我只是在测试):

ngOnInit(): void 
  this.rxStompService.watch('/topic/test').subscribe((message: Message) => 
    console.log(message.body);
  );


public test(): void 
  this.rxStompService.publish( destination: '/hello' );

有没有办法实际附加令牌?请注意,我使用的是刷新令牌,因此每 10 分钟会生成一个新的访问令牌,并且必须为每个请求使用一个新的访问令牌。

其次,如何在 spring 端点中提取令牌?在其他情况下,我会使用HttpServletRequest 并提取授权标头,但是如何使用套接字执行此操作?我需要这个,因为我需要使用发出请求的人的用户名(一个简单的解决方法是在正文中传递用户名,但如果可能的话,我希望用 JWT 保护它)。

@MessageMapping("/hello")
@SendTo("/topic/test")
public void createGameMP(HttpServletRequest request) 
    log.info("HI");
    log.info(request.getHeader(AUTHORIZATION).substring("Bearer ".length())); // obvious error

【问题讨论】:

【参考方案1】:

你可以使用Interceptor拦截websocket请求并在请求中设置token。

    定义自定义 HandshakeInterceptor
public class MyHandshakeInterceptor implements HandshakeInterceptor 

    private final static String X_AUTH_TOKEN = "x-auth-token";

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes)
            throws Exception 
        
        if (request instanceof ServletServerHttpRequest) 
            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
            HttpServletRequest httpServletRequest = servletRequest.getServletRequest();
            String token = httpServletRequest.getParameter(X_AUTH_TOKEN);
            if (null == token) 
                httpServletRequest.setParameter(X_AUTH_TOKEN, "xxxxx");//todo token value
            
        
        return true;
    

    配置
@Bean
public HandshakeInterceptor getHandshakeInterceptor() 
    return new MyHandshakeInterceptor();

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) 
    registry.addEndpoint("/wse").setAllowedOrigins("*").setInterceptors(myHandshakeInterceptor);
    registry.addEndpoint("/wss").setAllowedOrigins("*").setInterceptors(myHandshakeInterceptor);

【讨论】:

似乎无法正常工作。 httpServletRequest.getParameter("x-auth-token") 为空。我猜我必须在前端的 stomp 配置中设置 beforeConnect,但它仍然不起作用。我在原始帖子中编辑了 rxStompConfig 以显示我所做的更改。 @qlabfgerkaSmurf 您好,您可以实现ChannelInterceptor 并覆盖afterSendCompletion() 方法,设置令牌以在StompCommand CONNECT 时请求。然后就可以在Interceptor中获取token了。

以上是关于使用 Stomp 在 Spring Boot 中访问 JWT 令牌的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot 应用程序中向 STOMP CREATED 消息添加自定义标头?

SockJS over stomp 使用 angular2 和 spring boot

Spring Boot Stomp-Transaction Sockjs: ERROR message=[Bad transaction] Invalid transaction identifier

Spring Boot+STOMP解决消息乱序问题

Spring Boot + Stomp over WS 与嵌入式 Artemis 代理“目标不存在”

带有 stomp js 的 Spring Boot Websocket:我不断收到哎呀!与 http://localhost:8080/ws 的连接丢失