Spring Boot WebFlux Reactive MongoDB: как переключать базу данных при каждом запросе? - PullRequest
0 голосов
/ 02 апреля 2020

Я работаю над проектом SaaS, используя Spring WebFlux и Reactive MongoDB. Это должно быть приложение MultiTenant, и каждый арендатор должен использовать свою собственную базу данных.

На данный момент я просто добавил зависимость Reactive MongoDB к pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

Затем я расширил AbstractReactiveMongoConfiguration , чтобы обеспечить MongoClient и имя_базы_данных:

import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration;

@Configuration
public class DatabaseConfiguration extends AbstractReactiveMongoConfiguration {
    @Override
    public MongoClient reactiveMongoClient() {
        System.out.println("ReactiveMongoClient");
        return MongoClients.create();
    }

    @Override
    protected String getDatabaseName() {
        System.out.println("DataBase name");
        return "gateway";
    }
}

Все приложение представляет собой сервер ресурсов OAuth 2.0, и я могу получить TenantID из Аутентификация в ReactiveSecurityContextHolder .

public Mono<String> tenantID() {
    return ReactiveSecurityContextHolder.getContext()
            .switchIfEmpty(Mono.empty())
            .flatMap((securityContext) -> {
                Authentication authentication = securityContext.getAuthentication();

                if (authentication instanceof CustomAuthenticationToken) {
                    CustomAuthenticationToken customAuthenticationToken = (customAuthenticationToken) authentication;
                    Jwt jwt = customAuthenticationToken.getToken();

                    String issuer = jwt.getIssuer().toString();
                    return Mono.justOrEmpty(issuer);
                }

                return Mono.empty();
            });
}

Каков следующий шаг для переключения базы данных на основе пользователя (Аутентификация) выполняет запрос?

ОБНОВЛЕНИЕ:

Это почти близко к цели, но почти один год go @ mp911de сказал, что это невозможно. Интересно, возможно ли это сейчас? Как я могу реализовать действительно реактивную ReactiveMongoDatabaseFactory , которая возвращает Mono , чтобы я мог получить доступ к SecurityContext, а следовательно, и к аутентификации, перед возвратом MongoDatabase ?

1 Ответ

0 голосов
/ 03 апреля 2020

У меня была такая же проблема несколько месяцев назад go, и я хотел поделиться тем, как я ее решил.

Решение 1: сделать это самостоятельно

Spring делает не предоставлять готовые решения для этой проблемы. Несколько месяцев go я создал доказательство того, как ее решить, и только что опубликовал пример проекта на Github.

spring-mongodb-multi-tenancy-example

Вкратце: я создал пользовательский MultiTenancyReactiveMongoTemplate, который внутренне делегирует фактическому ReactiveMongoTemplate на основе tenantId из subscriberContext . tenantId извлекается из заголовка http-запроса в пользовательском WebFilter, который помещает его в subscriberContext .

Этот обходной путь работает в большинстве случаев, а также поддерживает автоматическое создание индекса и использование ReactiveMongoRepository.

Но также имеет некоторые ограничения, так как транзакции, IndexOps для MultiTenancyReactiveMongoTemplate или ReactiveGridFSTemplate не работают с предоставленным решением. Некоторые вещи могут быть реализованы с помощью других делегирующих «шаблонов», но некоторые вещи никогда не будут работать, поскольку эти операции просто возвращают скалярные значения (без Publisher), и в этих случаях нет доступа к subscriberContext.

Если вам не нужны эти функции, вы, вероятно, могли бы go с этим решением.

Решение 2:

Вы раскручиваете и настраиваете экземпляры службы для каждого арендатора / клиента и ставите обратный прокси «до» этих сервисов. Обратный прокси-сервер решает, какой сервис следует использовать для обработки запроса. Обратный прокси может быть реализован очень просто, например, Spring Cloud Gateway , который позволяет легко реализовать предикаты , которые решают (например, на основе токена аутентификации), какую службу следует использовать.

С такими технологиями, как CloudFoun dry или Kubernetes, уже нетрудно организовать развертывание этих служб, определяемых арендатором c, и это решение также упрощает мониторинг, оповещение или оповещение специалиста арендатора c. равномерный биллинг.

Мы выбрали решение 2 , потому что в целом это было проще и масштабировалось для нас лучше.

...