在stomp websocket spring boot 2中自定义错误消息

问题描述 投票:0回答:1

我使用Spring Boot 2 WebSocket + SockJS + STOMP。

当客户端使用ChannelInterceptor方法连接preSend时,我有JWT授权。

@Component
public class WebSocketChannelInterceptor implements ChannelInterceptor {

    private final TokenUtils tokenUtils;

    private final AuthenticationManager websocketAuthenticationManager;

    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketChannelInterceptor.class);

    public WebSocketChannelInterceptor(TokenUtils tokenUtils, AuthenticationManager websocketAuthenticationManager) {
        this.tokenUtils = tokenUtils;
        this.websocketAuthenticationManager = websocketAuthenticationManager;
    }

    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {

        LOGGER.info("WEBSOCKETCHANNELINTERCEPTOR -> "+message.toString());

        StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);

        if (accessor != null && StompCommand.CONNECT.equals(accessor.getCommand())) {
            List<String> headers = accessor.getNativeHeader(AUTHORIZATION);
            accessor.setUser(websocketAuthenticationManager.authenticate(new JWTTokenAuthentication(tokenUtils.resolveToken(headers != null ? headers.get(0) : null))));
        }

        return message;
    }

    @Override
    public boolean preReceive(MessageChannel channel) {
        LOGGER.info("preReceive");
        return true;
    }

}

AuthenticationManager会:

@Component("websocketAuthenticationManager")
@AllArgsConstructor
public class WebsocketAuthenticationManager implements AuthenticationManager {

    private final TokenUtils tokenUtils;

    private final ClientRepository clientRepository;

    private final OperatorRepository operatorRepository;

    @Override
    @Transactional(readOnly = true)
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        JWTTokenAuthentication jwtTokenAuthentication = (JWTTokenAuthentication) authentication;

        String token = jwtTokenAuthentication.getToken();

        if(tokenUtils.validateToken(token)) {

            RoleType role = RoleType.get(tokenUtils.get("role", token));

            if(role == null) {
                throw throwBadCredentialsException("Unknown role");
            }

            switch (role) {
                case OPERATOR:

                    Optional<OperatorEntity> operator = operatorRepository.findByLogin(tokenUtils.get("login", token));

                    if(operator.isPresent()) {
                        return new WebsocketOperatorDetails(token, OperatorDetails.builder().role(role.toString()).operator(operator.get()).build());
                    } else {
                        throw throwBadCredentialsException("Operator not found");
                    }

                case CLIENT:

                    Optional<ClientEntity> client = clientRepository.findByHash(tokenUtils.get("hash", token));

                    if(client.isPresent()) {
                        return new WebsocketClientDetails(token, ClientDetails.builder().role(role.toString()).client(client.get()).build());
                    } else {
                        throw throwBadCredentialsException("Client not found");
                    }
                case OWNER:
                    throw throwBadCredentialsException("Access denied");
                default:
                    throw throwBadCredentialsException("Unknown role");
            }

        } else {
            throw throwBadCredentialsException("Invalid token");
        }

    }

    private MessagingException throwBadCredentialsException(String message) {

        Map<String, Object> headers = new HashMap<>();

        headers.put("status", StatusType.UNAUTHORIZED);
        headers.put("message", message);

        return new MessagingException(new MutableMessage<>(new MessageHeaders(headers)));
    }

}

在AuthenticationManager中,如果出错,我会抛出错误。

在客户端,我得到下一个内容:

{  
   "command":"ERROR",
   "headers":{  
      "content-length":"0",
      "message":"Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.authentication.AuthenticationCredentialsNotFoundException\\c Invalid token"
   },
   "_binaryBody":{  

   },
   "isBinaryBody":true,
   "escapeHeaderValues":false,
   "skipContentLengthHeader":false,
   "_body":""
}

如何更改代码以发送带有效负载的错误消息?

谢谢。

spring-boot error-handling spring-websocket stomp
1个回答
0
投票

您可以使用有效负载和标头构造MutableMessage:

new MutableMessage<String>("payload", headers);

查看类MutableMessage中的构造函数:

public MutableMessage(T payload, Map<String, Object> headers) {
    Assert.notNull(payload, "payload must not be null");
    this.payload = payload;

    this.headers = new MutableMessageHeaders(headers);

    if (headers != null) {
        this.headers.put(MessageHeaders.ID, headers.get(MessageHeaders.ID));
        this.headers.put(MessageHeaders.TIMESTAMP, headers.get(MessageHeaders.TIMESTAMP));
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.