Ple*_*usz 6 java spring spring-security spring-messaging spring-websocket
问题
有没有办法全局处理MessageDeliveryException
Spring WebSocket 模块中由错误(通常权限不足)引起的Spring Messaging ?
用例
我已经通过 STOMP 实现了 Spring WebSockets 以支持我的 web 应用程序中的 ws 连接。为了保护 websocket 端点,我创建了授权用户在 STOMP CONNECT 时间启动 STOMP 会话的拦截器(如 Spring 文档中 22.4.11 部分的建议):
@Component
public class StompMessagingInterceptor extends ChannelInterceptorAdapter {
// Some code not important to the problem
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor headerAccessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
switch (headerAccessor.getCommand()) {
// Authenticate STOMP session on CONNECT using jwt token passed as a STOMP login header - it's working great
case CONNECT:
authorizeStompSession(headerAccessor);
break;
}
// Returns processed message
return message;
}
// Another part of code not important for the problem
}
Run Code Online (Sandbox Code Playgroud)
并包含 spring-security-messaging 配置以在消息传递时添加对权限的一些细粒度控制:
@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.simpTypeMatchers(
SimpMessageType.CONNECT,
SimpMessageType.DISCONNECT,
SimpMessageType.HEARTBEAT
).authenticated()
.simpSubscribeDestMatchers("/queue/general").authenticated()
.simpSubscribeDestMatchers("/user/queue/priv").authenticated()
.simpDestMatchers("/app/general").authenticated()
.simpDestMatchers("/user/*/queue/priv").hasAuthority("ADMIN")
.anyMessage().denyAll();
}
@Override
protected boolean sameOriginDisabled() {
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
首先 - 此配置按预期工作,问题是当 websocket 通信期间发生一些安全异常时(比如没有管理员权限的用户尝试在“/user/{something}/queue/priv”端点上发送消息)它将以org.springframework.messaging.MessageDeliveryException
正在上升和:
message
字段。我想做的是捕捉(如果可能的话在全球范围内) DeliveryException
,检查是什么导致它并相应地创建我自己的消息以在 STOMP ERROR 帧中返回(可以说一些错误代码,例如 403 来模仿 HTTP)而不是抛出原始异常进一步只是用我的记录器记录一些警告。是否可以?
我尝试过的
在寻找解决方案时,我发现有些人使用@MessageExceptionHandler
捕获消息传递异常,Spring 4.2.3(我使用的版本)文档在 25.4.11 部分中只在这里提到了一次。我试着像这样使用它:
@Controller
@ControllerAdvice
public class WebSocketGeneralController {
...
@MessageExceptionHandler
public WebSocketMessage handleException(org.springframework.messaging.MessageDeliveryException e) {
WebSocketMessage errorMessage = new WebSocketMessage();
errorMessage.setMessage(e.getClass().getName());
return errorMessage;
}
}
Run Code Online (Sandbox Code Playgroud)
但似乎任何时候都没有调用方法(尝试捕获不同的异常,只是Exception
包括 - 没有结果)。我还应该研究什么?
它不起作用,因为 @ControllerAdvice 从传递调度程序 servlet 的请求中捕获异常。当您保护端点时,如果有人发出未经授权的请求,该请求不会通过调度程序 servlet。该请求被 spring 拦截器捕获。