当前位置: 首页 > 知识库问答 >
问题:

无法向执行程序发送消息可订阅通道[客户端入站通道]

韦棋
2023-03-14
    I developed a mobile chat application with springboot,spring security,spring websockets ,stomp and sockjs. Server running at port 8082 and client running at 8100 port.
        I am using angular and sockjs client to send requests.when I try to connect to STOMP end point its giving the error at developer console(front end) and back end console.Below is the track trace,
        From Developer console:

        Opening Web Socket...
        stomp.min.js (line 8)
        GET http://localhost:8082/ws/info?t=1451547968350

        200 OK
        565ms

        sockjs-1.0.1.js (line 1610)
        Web Socket Opened...
        stomp.min.js (line 8)

                    CONNECT
                    login:test
                    passcode:test
                    accept-version:1.1,1.0
                    heart-beat:10000,10000

        **<<< ERROR message:Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.access.AccessDeniedException\c Access is denied
        content-length:0*
    Back end Error **:**
        org.springframework.messaging.MessageDeliveryException: Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.access.AccessDeniedException: Access is denied
        at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:127) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:104) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.web.socket.messaging.StompSubProtocolHandler.handleMessageFromClient(StompSubProtocolHandler.java:280) ~[spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.web.socket.messaging.SubProtocolWebSocketHandler.handleMessage(SubProtocolWebSocketHandler.java:317) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.web.socket.handler.WebSocketHandlerDecorator.handleMessage(WebSocketHandlerDecorator.java:75) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE

    **Angular and sockjs code files:**

    chatController.js**

        angular.module('letsCatchApp').controller(
        'chatController',
        function($scope, $location, $interval, toaster, chatSocket,$state) {
              var typing = undefined;
              $scope.username     = '';
                $scope.sendTo       = 'everyone';
                $scope.participants = [];
                $scope.messages     = [];
                $scope.newMessage   = ''; 

                $scope.sendMessage = function() {
                    console.log('22222');
                    var destination = "http://localhost:8082/app/chat.message";

                    if($scope.sendTo != "everyone") {
                        destination = "http://localhost:8082/app/chat.private." + $scope.sendTo;
                        $scope.messages.unshift({message: $scope.newMessage, username: 'you', priv: true, to: $scope.sendTo});
                    }

                    chatSocket.send(destination, {}, JSON.stringify({message: $scope.newMessage}));
                    $scope.newMessage = '';
                };

                $scope.startTyping = function() {
                  // Don't send notification if we are still typing or we are typing a private message
                    if (angular.isDefined(typing) || $scope.sendTo != "everyone") return;

                    typing = $interval(function() {
                            $scope.stopTyping();
                        }, 500);

                    chatSocket.send("http://localhost:8082/topic/chat.typing", {}, JSON.stringify({username: $scope.username, typing: true}));
                };

                $scope.stopTyping = function() {
                    console.log('44444');
                    if (angular.isDefined(typing)) {
                        $interval.cancel(typing);
                        typing = undefined;

                        chatSocket.send("http://localhost:8082/topic/chat.typing", {}, JSON.stringify({username: $scope.username, typing: false}));
                    }
                };

                $scope.privateSending = function(username) {
                    console.log('55555');
                        $scope.sendTo = (username != $scope.sendTo) ? username : 'everyone';
                };

                $scope.initStompClient = function() {
                    console.log('66666');
                    chatSocket.init('http://localhost:8082/ws');
                    console.log('66666rrrrrrrrrrrrrrrrr');
                    chatSocket.connect(function(frame) {

                        console.log('101010101010101');
                        $scope.username = frame.headers['user-name'];

                        chatSocket.subscribe("http://localhost:8082/app/chat.participants", function(message) {
                            console.log('7777');
                            $scope.participants = JSON.parse(message.body);
                        });

                        chatSocket.subscribe("http://localhost:8082/topic/chat.login", function(message) {
                            console.log('888888');
                            $scope.participants.unshift({username: JSON.parse(message.body).username, typing : false});
                        });

                        chatSocket.subscribe("http://localhost:8082/topic/chat.logout", function(message) {
                            console.log('99999');
                            var username = JSON.parse(message.body).username;
                            for(var index in $scope.participants) {
                                if($scope.participants[index].username == username) {
                                    $scope.participants.splice(index, 1);
                                }
                            }
                        });

                        chatSocket.subscribe("http://localhost:8082/topic/chat.typing", function(message) {
                            var parsed = JSON.parse(message.body);
                            if(parsed.username == $scope.username) return;

                            for(var index in $scope.participants) {
                                var participant = $scope.participants[index];

                                if(participant.username == parsed.username) {
                                    $scope.participants[index].typing = parsed.typing;
                                }
                            } 
                        });

                        chatSocket.subscribe("http://localhost:8082/topic/chat.message", function(message) {
                            console.log('88888');
                            $scope.messages.unshift(JSON.parse(message.body));
                        });

                        chatSocket.subscribe("http://localhost:8082/user/exchange/amq.direct/chat.message", function(message) {
                            console.log('9999');
                            var parsed = JSON.parse(message.body);
                            parsed.priv = true;
                            $scope.messages.unshift(parsed);
                        });

                        chatSocket.subscribe("http://localhost:8082/user/exchange/amq.direct/errors", function(message) {
                            toaster.pop('error', "Error", message.body);
                        });

                    }, function(error) {
                        console.log("errrooooooo=======   "+error);
                        toaster.pop('error', 'Error', 'Connection error ' + error);

                    });
                };

                //initStompClient();



            });

    chatService.js

        angular.module('letsCatchApp').service('chatSocket',
        function($rootScope,$http) {

                console.log('Chat service is called.... ');


            var stompClient;

             this.test = function() {
                 console.log('Chat service test... ');
                 return $http.get('http://localhost:8082/app/')
              }

         this.init = function(url) {
               console.log('Chat service init ... '+url);
                stompClient = Stomp.over(new SockJS(url));
                console.log('Chat service init ...end---- '+url);
          }

         this.connect = function(successCallback, errorCallback) {
             console.log('Chat service init ... connect');

                stompClient.connect({'login': 'test',
                    'passcode': 'test'}, function(frame) {
                   $rootScope.$apply(function() {
                        return successCallback(frame);
                    });
                    }, function(error) {
                        $rootScope.$apply(function(){
                            return errorCallback(error);
                    });
                });
            }

           this.subscribe = function(destination, callback) {
               console.log('Chat service init ... subscribe');
                stompClient.subscribe(destination, function(message) {
                        $rootScope.$apply(function(){
                            return callback(message);
                    });
              });   
            }

          this.send = function(destination, headers, object) {
                return stompClient.send(destination, headers, object);
            }

        });

    **WebsocketConfig files:**
        @Configuration
        @EnableWebSocketMessageBroker
        public class WebSocketConfig implements WebSocketMessageBrokerConfigurer{
        //AbstractSessionWebSocketMessageBrokerConfigurer {

         public static final String IP_ADDRESS = "IP_ADDRESS";
        // public static final String IP_ADDRESS = "IP_ADDRESS";

        @Override
        public void registerStompEndpoints(StompEndpointRegistry registry) {
           egistry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();

            registry.addEndpoint("/ws").setAllowedOrigins("*")
                    .setHandshakeHandler(new DefaultHandshakeHandler() {
                        @Override
                        protected Principal determineUser(
                                ServerHttpRequest request,
                                WebSocketHandler wsHandler,
                                Map<String, Object> attributes) {
                            Principal principal = request.getPrincipal();
                            if (principal == null) {
                                Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
                                authorities.add(new SimpleGrantedAuthority(
                                        "ANONYMOUS"));
                                principal = new AnonymousAuthenticationToken(
                                        "WebsocketConfiguration", "anonymous",
                                        authorities);
                            }
                            return principal;
                        }
                    }).withSockJS()
                    .setInterceptors(httpSessionHandshakeInterceptor());
        }

        @Bean
        public HandshakeInterceptor httpSessionHandshakeInterceptor() {
            return new HandshakeInterceptor() {

                @Override
                public boolean beforeHandshake(ServerHttpRequest request,
                        ServerHttpResponse response, WebSocketHandler wsHandler,
                        Map<String, Object> attributes) throws Exception {
                    if (request instanceof ServletServerHttpRequest) {
                        ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
                        attributes.put(IP_ADDRESS,
                                servletRequest.getRemoteAddress());
                        attributes.put("Access-Control-Allow-Origin",
                                "*");
                    }
                    return true;
                }

                @Override
                public void afterHandshake(ServerHttpRequest request,
                        ServerHttpResponse response, WebSocketHandler wsHandler,
                        Exception exception) {

                }
            };
        }

        @Override
        public void configureMessageBroker(MessageBrokerRegistry registry) {
            System.out
                    .println("registering the endpoint ==of ===/queue/===========");
            registry.enableSimpleBroker("/queue/", "/topic/", "/exchange/");
            // registry.enableStompBrokerRelay("/queue/", "/topic/", "/exchange/");
            registry.setApplicationDestinationPrefixes("/app");
        }

        @Override
        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> arg0) {

        }

        @Override
        public void addReturnValueHandlers(
                List<HandlerMethodReturnValueHandler> arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void configureClientInboundChannel(ChannelRegistration arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void configureClientOutboundChannel(ChannelRegistration arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public boolean configureMessageConverters(List<MessageConverter> arg0) {
            return false;
        }

        @Override
        public void configureWebSocketTransport(WebSocketTransportRegistration arg0) {
           // TODO Auto-generated method 

        }
HI Artem Bilan,Thanks for your reply.As per your comments,I am sharing the security config.
**WebsecurityConfig.java**
    @Configuration
    @EnableWebSecurity
    @EnableRedisHttpSession
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

        @Autowired
        private CustomUserDetailsService customUserDetailsService;

        @Autowired
        private RoleService roleService;

        /**
         * This section defines the user accounts which can be used for
         * authentication as well as the roles each user has.
         */
        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(customUserDetailsService);
        }

        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers(HttpMethod.POST, "/person/**")
                    //.antMatchers(HttpMethod.OPTIONS, "/**")
                    .antMatchers(HttpMethod.GET, "/lookup/**")
                    .antMatchers(HttpMethod.POST, "/upload/image/**")
                    .antMatchers(HttpMethod.GET, "/ws/**")
                    .antMatchers(HttpMethod.GET, "/topic/**")
                    .antMatchers(HttpMethod.GET, "/app/**");

        }

        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            Iterable<com.sergialmar.wschat.model.Role> roleIterable = roleService.getRoles();
            List<Role> roleList = new ArrayList<Role>();

            Iterator<Role> iterator = roleIterable.iterator();
            while (iterator.hasNext()) {
                Role role = iterator.next();
                roleList.add(role);
                System.out.println("Roles : " + role.getName());
            }

            String[] roles = new String[roleList.size()];

            for (int roleIndex = 0; roleIndex < roleList.size(); roleIndex++) {
                roles[roleIndex] = roleList.get(roleIndex).getName();
            }

            http.httpBasic().and().authorizeRequests()
                    .antMatchers(HttpMethod.GET, "/**").hasAnyAuthority(roles)
                    .antMatchers(HttpMethod.POST, "/**").hasAnyAuthority(roles)
                    .antMatchers(HttpMethod.PUT, "/**").hasAnyAuthority(roles)
                    .antMatchers(HttpMethod.DELETE, "/**").hasAnyAuthority(roles)
                    .antMatchers(HttpMethod.OPTIONS, "/**").hasAnyAuthority(roles)

                    .and().csrf().disable();
            http.headers().frameOptions().disable();
        }

    }

共有1个答案

李星辰
2023-03-14

JS是否在头中添加身份验证令牌?

var headers = {};
    var csrf = self.csrfToken();
    headers[csrf.headerName] = csrf.token;
    headers['X-AUTH-TOKEN'] = AUTH_TOKEN;
    stompClient.connect(headers, function(frame) );

暂时禁用与安全相关的配置,例如:AbstractSecurityWebSocketMessageBrokerConfigurer:

@Override
protected boolean sameOriginDisabled() {
    return true;
}




    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {

        messages
                .simpTypeMatchers(SimpMessageType.CONNECT,
                        SimpMessageType.HEARTBEAT,
                        SimpMessageType.UNSUBSCRIBE,
                        SimpMessageType.DISCONNECT)
                .permitAll()
                .anyMessage().authenticated() //or permitAll
                .simpDestMatchers("/**").authenticated();//or permitAll

}

WebSecurityConfigurerAdapter:
    http.csrf().disable();
    http.headers().frameOptions().disable()
                 .httpStrictTransportSecurity().disable();
 类似资料:
  • 问题内容: 我只能在用户的套接字ID直接存储在io.sockets.on(’connect’)函数中时向用户发出消息。我不知道为什么在登录后尝试存储其套接字ID时为什么不起作用。 加工: 无法运作: JavaScript客户端代码段 解决方案:感谢@alessioalex, 我不得不从登录页面中删除对socket.io的引用,并将以下内容添加到io.sockets.on(’connection’)

  • 问题内容: 所以现在,我正在制作一个基于客户端服务器应用程序的多线程。在服务器端,我为接受的每个连接创建了一个线程。 在线程类中,我创建了一种将命令发送到客户端的方法。我只想要的是如何将参数发送到所有正在运行的客户端?为简单起见,我只想使此服务器向所有连接的客户端发送消息。 我已经阅读了这篇文章,并从此链接中找到方法。但是,当我尝试使用自己的代码时,中没有类似的方法。 好的,这是我的服务器和线程示

  • 当我提交表单时,我在浏览器控制台中看到“emit”消息,所以我知道表单提交事件正在触发,但我没有在服务器上收到测试消息。客户端或服务器端似乎什么也没发生,“socket.emit”函数似乎什么也没做。 我做错了什么?

  • 我尝试将Spring与websocket一起使用。我从本教程开始调查。 在我的侧客户端,我有类似的东西来初始化到服务器的连接: 它工作得很好,在我的控制器中,我可以在下面的类中执行我的过程: 现在我想做的是让一个线程向监听“/主题/问候”的客户端发送消息。我这样写Runnable类: 这样完成了我的控制器: 该方法采用光电控制器。fireGreeting按我的要求调用,但客户端没有发生任何事情。有

  • 我后来理解对了。实际上,我需要一条来自android客户端的MQTT消息发送到所有其他客户端,所以我想在消息正文中包含publish关键字,这是非常错误的。MQTT本身将接收到的消息发送给所有提供的客户端,如果客户端订阅了该主题的话。

  • 主要内容:一、通知,二、源码分析,三、总结一、通知 在Redis中,既可以实现消息的发送又可以实现订阅,也就是常说的发布/订阅。它的主要逻辑实现在nofigy.c和module.c、pubsub.c中,其实通知做为一种辅助功能,是易用性的一种良好的接口。Redis的通知功能是一种即时在线通知功能,如果CS端断线后,相关的消息就无法再次通知,也就是说,消息机制没有保存和重发功能。这也是为了实现设计上的简单和功能实现的鲁棒性的考虑,至于以后会