Spring Security, обновление SecurityContextHolder

У меня многопользовательская среда, одна база данных с отдельной схемой для каждого арендатора.

При входе пользователя я загружаю арендатора по умолчанию, и все работает отлично. Я создаю метод switchTenant, который должен переключать текущий арендатор (по умолчанию) на выбранный. У меня есть частично работающее решение, где я сохраняю эту информацию в HttpSession. Все работает, с некоторыми побочными эффектами, например: при перезапуске tomcat пользователям необходимо повторно войти в систему, или пользователи Android при завершении работы приложения теряют сеанс.

Пытался найти лучшее решение для замены HttpSession на сохранение текущей информации о арендаторе в SecurityContext. И, конечно же, я потерпел неудачу, поэтому я прошу вас о помощи.

Вот соответствующий код, который я пытаюсь заставить работать:

ТенантПерехватчик (здесь все нормально)

...
@Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
        String schema = SecurityUtils.getCurrentSchema().orElse("");
        if (schema.equals("")) {
            TenantContext.setCurrentTenant("public");
        } else {
            TenantContext.setCurrentTenant(schema);
        }
        return true;
    }
...

Вспомогательный класс SecurityUtils (тут тоже все нормально)

...
public static Optional<String> getCurrentSchema() {
        SecurityContext securityContext = SecurityContextHolder.getContext();
        return Optional.ofNullable(securityContext.getAuthentication()).map(authentication -> {
            if (authentication.getPrincipal() instanceof TenantUser) {
                TenantUser springSecurityUser = (TenantUser) authentication.getPrincipal();
                return springSecurityUser.getCurrentSchema();
            }
            return null;
        });
    }
...

Класс обслуживания (для которого мне нужно исправить)

...
public void switchTenant(Tenant tenant) {
        Optional<TenantDTO> tenantExist = this.findAllUserTenants().stream()
            .filter(t -> t.getName().equals(tenant.getName())).findFirst();
        if (tenantExist.isPresent()) {

            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            Authentication newAuth = null;
            if (auth.getClass() == UsernamePasswordAuthenticationToken.class) {
                TenantUser principal = (TenantUser) auth.getPrincipal();
                principal.setCurrentSchema(tenant.getSchema());
                newAuth = new UsernamePasswordAuthenticationToken(principal, auth.getCredentials(), auth.getAuthorities());
            }
            SecurityContextHolder.getContext().setAuthentication(newAuth);
...

Класс TenantUser

public class TenantUser extends org.springframework.security.core.userdetails.User {

    private String userId;

    private String currentSchema;

    public TenantUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
        super(username, password, authorities);
    }
...

Несмотря ни на что, эта строка кода: SecurityContextHolder.getContext().setAuthentication(newAuth); всегда дает мне старую аутентификацию, а не ту, у которой обновлена ​​текущая схема арендатора.

Спасибо за помощь.

0
0
414
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Подход был плохой. Поскольку я использую токен jwt для аутентификации, лучший способ — сохранить текущую схему арендатора в токен. При переключении арендатора я обновил токен с новой текущей схемой и отправил его обратно клиенту.

Другие вопросы по теме