Vaadin отсутствует SpringSecurityContext в методе обратного вызова StreamResource - PullRequest
3 голосов
/ 21 марта 2019

У меня есть простой пример StreamResource, где SpringSecurityContext таинственным образом исчезает при нажатии на ссылку для загрузки.Обычно при щелчке привязки загрузки createInputStream вызывается метод для создания файла загрузки, но при выполнении этого метода SecurityContext имеет значение null.Ниже приведен упрощенный пример, который воспроизводит проблему.

public class HomeView extends VerticalLayout {

public HomeView() {
    Anchor anchor = new Anchor();
    anchor.add("DOWNLOAD");
    anchor.setHref(new StreamResource("file", () -> createInputStream()));
    add(anchor);
    // SecurityContext returns correct value and is not null.
    System.err.println(SecurityContextHolder.getContext());
    System.err.println("Thread name in constructor : " + Thread.currentThread().getName());
}

private InputStream createInputStream() {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try {
        outputStream.write("text".getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    }
    // SecurityContextHolder.getContext() returns null here. Why?
    System.err.println(SecurityContextHolder.getContext());
    System.err.println("Thread name in createInputStream() : " + Thread.currentThread().getName());
    return new ByteArrayInputStream(outputStream.toByteArray());
}}

Когда этот код выполняется, я получаю следующие сообщения.

org.springframework.security.core.context.SecurityContextImpl@db426455: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@db426455: Principal: org.springframework.security.core.userdetails.User@983d0d8b...Rest omitted

Thread name in constructor : http-nio-8080-exec-4

org.springframework.security.core.context.SecurityContextImpl@ffffffff: Null authentication

Thread name in createInputStream() : http-nio-8080-exec-9

Но я обнаружил, что одним из способов решения этой проблемы являетсяустановите SecurityContext вручную в методе createInputStream.Ниже приведен пример.

public class HomeView extends VerticalLayout {

SecurityContext context;

public HomeView() {
    Anchor anchor = new Anchor();
    anchor.add("DOWNLOAD");
    anchor.setHref(new StreamResource("file", () -> createInputStream()));
    add(anchor);
    // Save Context to a variable
    context = SecurityContextHolder.getContext();
    System.err.println(SecurityContextHolder.getContext());
}

private InputStream createInputStream() {
    // Set SecurityContext before accessing it.
    SecurityContextHolder.setContext(context);
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try {
        outputStream.write("text".getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    }
    // SecurityContextHolder.getContext() no longer returns null.
    System.err.println(SecurityContextHolder.getContext());
    return new ByteArrayInputStream(outputStream.toByteArray());
}}

В итоге я получил этот вопрос. Почему Spring SecurityContext потерян в первом примере, есть ли лучший способ исправить это или я застрял во втором примере?

В качестве примечания я понял, что компонент загрузки Vaadin имеетта же проблема.SecurityContext теряется в addSucceededListener методе обратного вызова.

Я использую Vaadin 13.0.1 и Spring Boot 2.1.3.

1 Ответ

2 голосов
/ 25 марта 2019

Проблема была связана с конфигурацией Spring Security WebSecurity, приведенной ниже примера, который является прямой копией из примера приложения Vaadin's Bakery.

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring()
       .antMatchers(
               // Vaadin Flow static resources
               "/VAADIN/**", // This was the problematic spot

               //Rest of configuration omitted for simplicity
}

Проблема заключалась в том, что динамически создаваемые файлы с помощью StreamResource или компонента загрузки сопоставлялись сURL, который имеет следующий префикс /VAADIN/dynamic/resource/**.В приведенной выше конфигурации мы сообщаем Spring Security с /VAADIN/** до игнорировать все запросы, начиная с /VAADIN/.Это заставляет Spring Security игнорировать все запросы HttpServletRequest, которые указывают на динамически создаваемый ресурс, поскольку Vaadin отображает их с префиксом /VAADIN/dynamic/resource/** url.Когда Spring Security игнорирует запрос HttpServletRequest, его SpringSecurityContext будет пустым.См. Документацию WebSecurity.ignoring () .

Эту проблему можно исправить, переименовав /VAADIN/** в /VAADIN/static/**.Это не позволит Spring Security игнорировать запросы к динамическим ресурсам, и поэтому SpringSecurityContext будет доступен в методах обратного вызова StreamResource и Upload.Ниже рабочий пример.

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring()
       .antMatchers(
               // Vaadin Flow static resources
               "/VAADIN/static/**",

               //Rest of configuration omitted for simplicity
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...