# Stomp websocket setting ```java= package com.alp.config; import com.alp.jwt.exception.JwtTokenMalformedException; import com.alp.jwt.util.JwtUtil; import com.alp.util.CacheUtil; import com.nimbusds.jwt.JWTClaimsSet; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.listener.PatternTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.config.annotation.*; import org.springframework.web.socket.handler.WebSocketHandlerDecorator; import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory; import org.springframework.web.socket.server.support.DefaultHandshakeHandler; import javax.servlet.http.HttpServletRequest; import java.security.Principal; import java.util.List; import java.util.Map; @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer/*AbstractSecurityWebSocketMessageBrokerConfigurer*/ implements WebSocketMessageBrokerConfigurer { private static final Logger log = LoggerFactory.getLogger(WebSocketConfig.class); @Autowired private JwtUtil jwtUtil; @Autowired private CacheUtil cacheUtil; @Override // 實現WebSocketMessageBrokerConfigurer中的此方法,配置消息代理(broker) public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker( "/DSN001", "/DSN002"); // 啟用SimpleBroker,使得訂閱到此"DSN001"、"DSN002"前綴的客戶端可以收到工作站通知. } @Override // 用來註冊Endpoint,"DSN001"、"DSN002"即為客戶端嘗試建立連接的地址。 public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/DSN001", "/DSN002").setAllowedOrigins("*").setHandshakeHandler(handshakeHandler()).withSockJS(); } /*@Override public void configureClientInboundChannel(ChannelRegistration registration) { super.configureClientInboundChannel(registration); registration.setInterceptors(new ChannelInterceptorAdapter() { @Override public Message<?> preSend(Message<?> message, MessageChannel channel) { StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); log.info("accessor.getCommand():{}", accessor.getCommand()); if (StompCommand.CONNECT.equals(accessor.getCommand())) { //accessor.setUser(user); } return message; } }); }*/ @Override public void configureWebSocketTransport(WebSocketTransportRegistration registration) { super.configureWebSocketTransport(registration); registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() { @Override public WebSocketHandler decorate(WebSocketHandler handler) { return new WebSocketHandlerDecorator(handler) { @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { super.afterConnectionEstablished(session); log.info("afterConnectionEstablished:{}", session.getAttributes()); if (session.getAttributes().get("serviceTicket") != null) { log.info("----force close----"); session.close(CloseStatus.POLICY_VIOLATION); } } }; } }); } @Bean public UserAuthHandshakeHandler handshakeHandler() { return new UserAuthHandshakeHandler(); } public class UserAuthHandshakeHandler extends DefaultHandshakeHandler { @Override protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) { // return request.getPrincipal(); // Default authentication // Handshake url parameter ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) request; HttpServletRequest httpRequest = servletServerHttpRequest.getServletRequest(); //從連線的ws url的parameter取得參數 String jwtToken = httpRequest.getParameter("token"); if (StringUtils.isBlank(jwtToken)){ throw new JwtTokenMalformedException( "no jwt token" ); } JWTClaimsSet claims = jwtUtil.parseJwtToken( jwtToken ); String serviceTicket = claims.getJWTID(); attributes.put("serviceTicket",serviceTicket); log.info("request.getPrincipal(){}", request.getPrincipal()); log.info("remoteAddress:{}", request.getRemoteAddress().getAddress().getHostAddress()); log.info("get jwtToken:{}", jwtToken); return request.getPrincipal(); } } @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { super.addArgumentResolvers(argumentResolvers); } @Bean(name = "dsn001PatternTopic") public PatternTopic dsn001PatternTopic() { return new PatternTopic("/DSN001/*"); } @Bean(name = "dsn002PatternTopic") public PatternTopic dsn002PatternTopic() { return new PatternTopic("/DSN002/*"); } /** * 設置一個處理 Redis Pub/Sub 消息的監聽器 */ @Bean public RedisMessageListenerContainer redisMessageListenerContainer( @Qualifier("wsRedisConnectionFactory") RedisConnectionFactory connectionFactory, @Qualifier("DsN001Mod") MessageListener dsN001Mod, @Qualifier("dsn001PatternTopic") PatternTopic dsn001PatternTopic, @Qualifier("DsN002Mod") MessageListener dsN002Mod, @Qualifier("dsn002PatternTopic") PatternTopic dsn002PatternTopic) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.addMessageListener(dsN001Mod, dsn001PatternTopic); container.addMessageListener(dsN002Mod, dsn002PatternTopic); return container; } } ```