通过后端代理前端到mq的请求(stomp协议),主要是为了加权限验证。
这里的MQ指ActiveMQ。
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
stomp代理
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
/**
* stomp
*
* @author jimo
* @version 1.0.0
* @date 2020/5/15 11:31
*/
@Configuration
@EnableWebSocketMessageBroker
public class StompConfig implements WebSocketMessageBrokerConfigurer {
@Resource
private ActiveMqInfo activeMqInfo;
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint(activeMqInfo.getProxyPrefix()).setAllowedOrigins("*")
.withSockJS()
.setInterceptors(new WsHandShakeInterceptor());
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/queue", "/topic")
// .setTcpClient(createTcpClient());
.setRelayHost(activeMqInfo.getHost())
.setRelayPort(activeMqInfo.getPort())
// 给客户端的密码
.setClientLogin(activeMqInfo.getUsername())
.setClientPasscode(activeMqInfo.getPassword())
.setSystemLogin(activeMqInfo.getUsername())
.setSystemPasscode(activeMqInfo.getPassword());
}
}
鉴权拦截
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;
import java.util.Map;
/**
* 拦截websocket代理
*
* @author jimo
* @version 1.0.0
* @date 2020/5/15 16:51
*/
@Slf4j
public class WsHandShakeInterceptor implements HandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
// assert request instanceof HttpServletRequest;
// HttpServletRequest req = (HttpServletRequest) request;
try {
final String userName = WebUtil.getUserName(WebUtil.getHttpServletRequest());
log.info("用户{}访问MQ代理握手", userName);
} catch (Exception e) {
log.error("MQ代理握手异常:{}", e.getMessage());
return false;
}
return true;
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Exception exception) {
}
}
配置文件
activemq:
host: mq-host
port: 61613
username: xxx
password: xxx
proxy-prefix: /websocket/stomp/**
前端
使用SockJS
var url = "http://backend-host/websocket/stomp";
var sock = new SockJS(url);
sock.onopen = function() {
console.log('open');
sock.send('test');
};
sock.onmessage = function(e) {
console.log('message', e.data);
sock.close();
};
sock.onclose = function() {
console.log('close');
};
var stompClient = Stomp.over(sock);
var headers = {
login: 'xxx',
passcode: 'xxx',
// additional header
'client-id': 'my-client-id'
};
stompClient.connect({}, function (frame) {
// 这里的 /queue 和前面代理声明的broker要匹配
stompClient.subscribe('/queue/greetings', function (greeting) {
console.log(greeting);
});
});