带有 websockets 的 Spring 多租户应用程序?

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

我有一个正在运行的 Spring 多租户应用程序。它使用熟悉的线程局部变量和 Web 过滤器结构,并使用主机名(子域)来确定哪个租户处于活动状态。

但是浏览器也会打开一个 websocket 并发送消息。不知何故,我需要在那里做同样的事情;我需要将传入消息与租户(也称为用于启动 Websocket 的主机名)进行匹配。没有 Websocket 过滤器的概念。

有一个 HandshakeInterceptor,可以在其中访问主机名,或者可以通过 WebSocketEventListener 访问,因此可能可以在那里构造一些东西。但我似乎找不到一种方法将传入消息(在 @Controller 类的 @MessageMapping 方法中)链接到任何合理的东西。

关于如何做到这一点有什么见解吗?

spring multi-tenant spring-websocket
1个回答
0
投票

这需要一些挖掘,但对于最终提出同样问题的人来说。将从 HttpServletRequest 确定租户 ID 的代码以及配置和日志记录(例如 MDC)的代码放在可重用静态方法中的 de TenantFilter 中。然后:

  1. 确定tenantId并将其存储在HandshakeInterceptor中
.addInterceptors(new HandshakeInterceptor() {
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {

        // Determine the tenantId (see TenantFilter)
        ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) request;
        HttpServletRequest httpServletRequest = servletServerHttpRequest.getServletRequest();
        String tenantId = TenantFilter.determineTenantId(httpServletRequest, ...);
        attributes.put("tenantId", tenantId);
        return true;
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
    }
})

  1. 在 WebsocketController 类的消息处理方法中,使用 Header 注解来获取属性并从中获取tenantId:
@MessageMapping("/SetNoteworthy")
public void browserToBackend(SetNoteworthy command, @Header("simpSessionId") String sessionId, @Header("simpSessionAttributes") Map<String, String> attributes) throws Exception {
    String tenantId = attributes.get("tenantId");

    if (LOG.isInfoEnabled()) LOG.info(BROWSER_TO_BACKEND + command);
    TenantFilter.setCurrentTenant(tenantId, ...);
}
© www.soinside.com 2019 - 2024. All rights reserved.