Позвольте мне предисловие, сказав, что для моего сценария будет отказано в доступе . Построен в Spring Boot с Spring Security 4. Я разрешаю любому подключиться к websocket и подписаться на тему, но я гарантирую возможность отправлять сообщения в эту тему со следующей конфигурацией безопасности сетевого сокета:Spring Websocket Security throwing AccessDeniedException
@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.simpSubscribeDestMatchers("/main-page-feed/thought-queue/**").permitAll()
.simpDestMatchers("/thought-bubble/push-to-queue/**").authenticated();
}
@Override
protected boolean sameOriginDisabled() {
return true;
}
}
Так что, когда вы пытаетесь отправить сообщение /thought-bubble/push-to-queue
в то время как неаутентифицированные, он отрицает вас (что правильно, я хочу это подчеркнуть, потому что только другие вопросы, которые я могу найти на это есть, когда исключение неправильно выброшены) и выбрасывает AccessDeniedException
. Я не понимаю, когда, в отличие от безопасности websocket, Spring HTTP-защита блокирует что-то и отказывается от доступа, она не генерирует исключение, она просто отправляет статус HTTP. Я пробовал использовать @ExceptionHandler
, AccessDenied обработчики, но ничего, что я пробовал, удалось поймать и обработать это исключение. Ниже представлена трассировка стека и другие соответствующие файлы, любые идеи оцениваются, потому что я довольно застрял. Я пробовал переходить через исходный код в debug, но я действительно не вижу, в чем проблема.
Трассировка стека:
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.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:104) ~[spring-messaging-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.messaging.StompSubProtocolHandler.handleMessageFromClient(StompSubProtocolHandler.java:298) ~[spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.messaging.SubProtocolWebSocketHandler.handleMessage(SubProtocolWebSocketHandler.java:307) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.handler.WebSocketHandlerDecorator.handleMessage(WebSocketHandlerDecorator.java:75) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator.handleMessage(LoggingWebSocketHandlerDecorator.java:56) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator.handleMessage(ExceptionWebSocketHandlerDecorator.java:58) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.delegateMessages(AbstractSockJsSession.java:382) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession.handleMessage(WebSocketServerSockJsSession.java:193) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.sockjs.transport.handler.SockJsWebSocketHandler.handleTextMessage(SockJsWebSocketHandler.java:92) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.handler.AbstractWebSocketHandler.handleMessage(AbstractWebSocketHandler.java:43) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.handleTextMessage(StandardWebSocketHandlerAdapter.java:110) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.access$000(StandardWebSocketHandlerAdapter.java:42) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:81) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:78) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:399) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.server.WsFrameServer.sendMessageText(WsFrameServer.java:106) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:500) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:295) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:131) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:69) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:148) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:802) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1410) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.6.jar:8.5.6]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_101]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_101]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.6.jar:8.5.6]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_101]
Caused by: org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor.preSend(ChannelSecurityInterceptor.java:71) ~[spring-security-messaging-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel$ChannelInterceptorChain.applyPreSend(AbstractMessageChannel.java:158) ~[spring-messaging-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:113) ~[spring-messaging-4.3.5.RELEASE.jar:4.3.5.RELEASE]
... 30 common frames omitted
Security Config:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserProfileService userProfileService;
@Autowired
private CustomAccessDeniedHandler accessDeniedHandler;
@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userProfileService);
auth.authenticationProvider(authenticationProvider());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userProfileService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/javascript/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http .httpBasic()
.and()
.authorizeRequests()
.antMatchers("/", "/index.html", "/home.html", "/getLatestPost", "/application-socket-conn/**").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler).and()
.csrf().disable();
}
}
Web Оправа Config:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
//Javascript connection subscribes to this URI
config.enableSimpleBroker("/main-page-feed");
//STOMP messages are sent to this URI + suffix
config.setApplicationDestinationPrefixes("/thought-bubble");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//URI used for SockJS connection
registry.addEndpoint("/application-socket-conn").withSockJS();
}
}
Пользовательские AccessDenied Handler (не ловя):
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Autowired
@Qualifier("clientOutboundChannel")
private MessageChannel clientOutboundChannel;
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
Message<String> message = new Message<String>() {
@Override
public String getPayload() {
return "Access denied.";
}
@Override
public MessageHeaders getHeaders() {
return null;
}
};
clientOutboundChannel.send(message);
}
}
Web Оправа контроллер
@RestController
public class WebSocketController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/push-to-queue")
public void pushThoughtToQueue(@Payload ThoughtEntity entity) throws Exception {
Date today = new Date(Calendar.getInstance().getTimeInMillis());
entity.setPostDate(today);
entity.setFavoriteCount(0);
this.simpMessagingTemplate.convertAndSend("/main-page-feed/thought-queue", entity);
}
}
Я думаю AffirmativeBased
класс, где это становится выброшено, но я не знаю, почему, или почему нормальная (не веб-розетка) пружина безопасность не делает этого, когда он лишает доступ к чему-то. Как я уже сказал, это правильно лишает доступ, но он бросает исключение во время выполнения и отправляет уродливую стеклу обратно клиенту через websocket.
UPDATE:
Я понял, что исключение или не авторизован пользователь, поэтому я думаю, что это другой вопрос. Как я уже сказал, я не использую ROLE
s для этого приложения, и я думаю, что это как-то связано с этим. В настоящее время я изучаю анонимные роли, потому что я думаю, что это связано с тем, что происходит.
Ну я попробовал почти все мыслимые и я не могу понять это так, поэтому любой ввод или идеи (независимо от того, как это диковинно) приветствуются на этом этапе. –