繁体   English   中英

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

[英]Customize error message in stomp websocket spring boot 2

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

当客户端在preSend方法中的ChannelInterceptor中连接时,我有 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;
    }

}

身份验证管理器:

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

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

谢谢。

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

您可以使用有效负载和标头构造 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));
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM