gpt4 book ai didi

java - 如何全局处理Spring WebSockets/Spring Messaging异常?

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:23:38 33 4
gpt4 key购买 nike

问题
有没有办法全局处理Spring WebSocket模块错误(通常权限不足)导致的Spring Messaging MessageDeliveryException

用例
我已经通过 STOMP 实现了 Spring WebSockets 以支持我的 webapp 中的 ws 连接。为了保护 websocket 端点,我创建了拦截器,授权用户在 STOMP CONNECT 时间启动 STOMP session (如 Spring 文档 here in 22.4.11 section 中所建议):

@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
}

并包含 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;
}
}

首先 - 此配置按预期工作,问题是在 websocket 通信期间发生某些安全异常时(假设没有管理员权限的用户试图在“/user/{something}/queue/priv”端点上发送消息)将以 org.springframework.messaging.MessageDeliveryException 结束,并且:

  • 正在将完整的异常堆栈跟踪记录到我的服务器日志中
  • 返回包含部分堆栈跟踪的 STOMP 错误帧,因为它是 message 字段。

我想做的是捕获(如果可能的话全局)DeliveryException,检查导致它的原因并相应地创建我自己的消息以在 STOMP ERROR 帧中返回(假设有一些错误代码就像模仿 HTTP 的 403 一样),而不是进一步抛出原始异常,只是用我的记录器记录一些警告。可能吗?

我尝试了什么
在寻找解决方案时,我发现有些人使用 @MessageExceptionHandler 来捕获消息传递异常,Spring 4.2.3(我使用的版本)文档仅提及一次 here in 25.4.11 section .我试着像这样使用它:

@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;
}
}

但似乎在任何时候都没有调用方法( try catch 不同的异常,只是 Exception 包括 - 没有结果)。我还应该检查什么?

最佳答案

@ControllerAdvice@MessageExceptionHandler 在业务逻辑级别上工作(如 @MessageMappingSimpMessagingTemplate) .

要处理 STOMP 异常,您需要在 STOMP 注册表中设置 STOMP 错误处理程序:

@Configuration
@EnableWebSocketMessageBroker
class WebSocketConfiguration : WebSocketMessageBrokerConfigurer {

override fun configureMessageBroker(registry: MessageBrokerRegistry) {
// ...
}

override fun registerStompEndpoints(registry: StompEndpointRegistry) {
registry.addEndpoint("/ws")

// Handle exceptions in interceptors and Spring library itself.
// Will terminate a connection and send ERROR frame to the client.
registry.setErrorHandler(object : StompSubProtocolErrorHandler() {
override fun handleInternal(
errorHeaderAccessor: StompHeaderAccessor,
errorPayload: ByteArray,
cause: Throwable?,
clientHeaderAccessor: StompHeaderAccessor?
): Message<ByteArray> {
errorHeaderAccessor.message = null
val message = "..."
return MessageBuilder.createMessage(message.toByteArray(), errorHeaderAccessor.messageHeaders)
}
})
}
}

关于java - 如何全局处理Spring WebSockets/Spring Messaging异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48688798/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com