WebSocket Stomp over SockJS - http自定义头



我在javascript客户端使用stomp.js而不是SockJS。我正在使用

连接到websocket
stompClient.connect({}, function (frame) {

践踏sockJS连接有2个http请求:

  1. 请求/info

客户端发送所有cookie。我也想发送自定义头(例如XSRF头),但没有找到这样做的方法。

@Rohitdev所以基本上你不能使用stompClient发送任何HTTP报头,因为STOMP是在websockets上的层,只有当websockets握手发生时,我们才有可能发送自定义报头。所以只有SockJS可以发送这个头,但由于某些原因不这样做:https://github.com/sockjs/sockjs-client/issues/196

自定义标题:

stompClient.connect({token: "ABC123"}, function(frame) { ... code ...});

不带自定义头:

stompClient.connect({}, function(frame) { ... code ...});

在Javascript中,您可以使用以下命令提取STOMP标头:

  username = frame.headers['user-name'];

在服务器端,如果你正在使用Spring框架,你可以实现一个拦截器来复制HTTP参数到WebSockets STOMP头。

public class HttpSessionHandshakeInterceptor_personalised implements HandshakeInterceptor {
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
            WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {

        // Set ip attribute to WebSocket session
        attributes.put("ip", request.getRemoteAddress());
        // ============================================= CODIGO PERSONAL
        ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
        HttpServletRequest httpServletRequest = servletRequest.getServletRequest();
//        httpServletRequest.getCookies();
//        httpServletRequest.getParameter("inquiryId");
//        httpServletRequest.getRemoteUser();
         String token = httpServletRequest.getParameter("token");

      ...
    }
}

对于没有STOMP参数的发送消息:

function sendMessage() {
     var from = document.getElementById('from').value;
     var text = document.getElementById('text').value;
            stompClient.send("/app/chatchannel", {},
               JSON.stringify({'from':from, 'text':text}));
}

,这里你是在传递参数到STOMP报头。

function sendMessage() {
     var from = document.getElementById('from').value;
     var text = document.getElementById('text').value;
            stompClient.send("/app/chatchannel", {'token':'AA123'},
               JSON.stringify({'from':from, 'text':text}));
}

如果您在服务器上使用Spring引导,则在方法中使用@Header(name = "token")注释

用法-

@Controller
public class SocketController {
    static final String token = "1234";
    @MessageMapping("/send")
    @SendTo("/receive/changes")
    public Object notify(MessageModel message, @Header(name = "token") String header)throws Exception {
        if(!header.equals(token)) {
            // return when headers do not match
            return("Unauthorized");
        }
        // return the model object with associated sent message
        return new MessageModel(message.getMessage());
    } 
}

你应该有一个MessageModel类与message变量和所需的getters, setterscontructor

前端使用Stomp

使用

function sendMessage() {
     var text = document.getElementById('text').value;
            stompClient.send("/send/message", {'token':'1234'},
               JSON.stringify({'message':text}));
}

要增加更多的安全性,您可以在Spring中使用CORS

您必须使用query作为参数,而不是在Header中使用Authorization。(? = token_2222)查询例如:var socket = new SockJS('/ws?query=token_2222');然后在HandshakeInterceptor中读到Sergio写的

SockJS JavaScript客户端不支持在发送SockJS请求时发送授权头。

Spring Java的STOMP客户端允许设置握手头:

WebSocketHttpHeaders handshakeHeaders = new WebSocketHttpHeaders();
handshakeHeaders.add(principalRequestHeader, principalRequestValue);

附加信息:https://www.toptal.com/java/stomp-spring-boot-websocket

你可以在Spring文档中找到很多关于这一点的信息:https://docs.spring.io/spring-framework/docs/current/reference/html/web.html websocket-stomp-authentication

简短总结:对于使用cookie的应用程序,集成非常好(Spring Security和其他)。

对于使用JWT的应用程序,可能的选项是:

1。在DefaultHandshakeHandler

的实现中添加一个请求参数和进程
var socket = new SockJS('/our-websocket?query=token_2222');

2。或者直接添加到消息的STOMP头:

//添加

var headers = {
        login: 'mylogin',
        passcode: 'mypasscode',
        // additional header
        'client-id': 'my-client-id'
    };
    stompClient.connect(headers, function (frame) {}

//处理地点

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void configureMessageBroker(final MessageBrokerRegistry registry) {
        registry.enableStompBrokerRelay("/topic")
                .setRelayHost("127.0.0.1")
                .setRelayPort(61613) //rabbitmq-plugins enable rabbitmq_stomp ; docker exec -it ID bash
                .setClientLogin("guest")
                .setClientPasscode("guest")
                .setUserRegistryBroadcast("/topic/registry") //позволяет отправлять сообщеня всем приватные сообщения всем юзерам
        ;
        registry.setApplicationDestinationPrefixes("/ws");
    }

    @Override
    public void registerStompEndpoints(final StompEndpointRegistry registry) {
        registry.addEndpoint("/our-websocket")
                .setHandshakeHandler(new UserHandshakeHandler())
                .setAllowedOriginPatterns("*")
                .withSockJS()
        ;
    }
    @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())) {
// 1) Perform authentication here using standard authentication providers (managers).
//2) Install the user in case of successful authentication or throw an error
                    accessor.setUser(new UserPrincipal("TEST USER 2"));
                }
                return message;
            }
        });
    }
}
 

相关内容

  • 没有找到相关文章

最新更新