Spring security csrf не работает с весенней сессией

Я использую весеннюю сессию версии 1.0.0.M1 и настроил ее для использования MapSessionRepository: sessionFilterChainReg.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST), false, dispatcherServletReg.getName());

@Bean(name = {"defaultSessionFilter", "sessionFilter"})
public SessionRepositoryFilter sessionFilter() {
    return new SessionRepositoryFilter((SessionRepository) applicationContext.getBean("sessionRepository"));
}


@Bean(name = { "defaultSessionRepository", "sessionRepository" })
public SessionRepository defaultSessionRepository() {
    return new MapSessionRepository();
}

а затем в веб-конфигурации:

    final FilterRegistration sessionFilterChainReg = servletContext.addFilter("sessionFilter", DelegatingFilterProxy.class);

Итак, у меня есть в моем register.jsp следующий скрытый элемент ввода:

<input type="hidden" id="${_csrf.parameterName}" name="${_csrf.parameterName}" value="${_csrf.token}"/>

И я вижу, что страница отображается с правильным токеном CSRF. Когда я отправляю запрос POST, срабатывает фильтр CSRF, и токен правильно передается фильтру, который вызывает HttpSessionCsrfTokenRepository:loadToken, и в строке 66 мы видим:

HttpSession session = request.getSession(false);

и теперь сеанс нулевой, поэтому репозиторий возвращает нулевой токен CSRF, а затем выдается MissingCsrfTokenException. Есть ли что-то еще, что мне нужно настроить?

Вот трассировка стека при попадании в строку 66 (их намного больше, но я думаю, что это важная часть):

at org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.loadToken(HttpSessionCsrfTokenRepository.java:66)
  at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:75)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
  at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
  at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
  at org.springframework.security.web.access.channel.ChannelProcessingFilter.doFilter(ChannelProcessingFilter.java:144)
  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
  at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
  at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
  at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
  at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1632)
  at org.springframework.session.web.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:83)
  at org.springframework.session.web.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:66)
  at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
  at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1632)

person Petar Tahchiev    schedule 05.10.2014    source источник
comment
Поддержка CSRF не создает сеанс, пока вы не подготовите представление, содержащее в нем токен CSRF. Где вы используете токен CSRF? Вам нужно представление (например, JSP, шаблон Thymeleaf, заголовок ответа и т. д.), которое содержит токен CSRF. Еще одна вещь, которую стоит попробовать, это работает без Spring Session?   -  person Rob Winch    schedule 07.10.2014
comment
Привет, Роб, я обновил вопрос. Да, он отлично работает без весеннего сеанса, и токен CSRF правильно передается фильтру, но сеанс, возвращаемый в HttpSessionCsrfTokenRepository:loadToken:66, имеет значение null.   -  person Petar Tahchiev    schedule 07.10.2014
comment
Можете ли вы посмотреть запрос, чтобы увидеть, какие файлы cookie присутствуют? Это может быть связано с github.com/spring-projects/spring-session/issues. /34 Если вы видите несколько сеансовых файлов cookie, вам следует удалить их все, а затем повторить попытку.   -  person Rob Winch    schedule 07.10.2014
comment
Привет, Роб, у меня было много файлов cookie (около 35), из которых только 1 назывался SESSION. Я удалил все куки и попробовал еще раз, но результат тот же - я получаю MissingCsrfTokenException. Также я только что заметил, что не только форма регистрации не работает, но и форма входа в систему теперь не работает - точно такая же проблема.   -  person Petar Tahchiev    schedule 07.10.2014
comment
Можете ли вы скопировать/вставить стек вызовов в сообщение из вашей IDE при добавлении точки отладки в HttpSessionCsrfTokenRepository:loadToken:66?   -  person Rob Winch    schedule 07.10.2014
comment
Привет, Роб, я вставил это в вопрос.   -  person Petar Tahchiev    schedule 07.10.2014
comment
На данный момент все выглядит правильно для меня. В любом случае вы можете создать небольшой пример проекта, который воспроизводит проблему?   -  person Rob Winch    schedule 08.10.2014


Ответы (1)


Обнаружил проблему - у меня самого был Filter, который обертывал объект HttpServletRequest, и фильтр срабатывал до SessionRepositoryFilter. Я не уверен, что это правильно, но чтобы заставить его срабатывать после SessionRepositoryFilter, я сделал это:

@Bean(name = {"defaultSessionFilter", "sessionFilter"})
public Filter sessionFilter() {
    CompositeFilter compositeFilter = new CompositeFilter();
    compositeFilter.setFilters(Arrays.asList(new SessionRepositoryFilter((SessionRepository) applicationContext.getBean("sessionRepository")), applicationContext.getBean("myFilter")));

    return compositeFilter;
}

который решает проблему.

person Petar Tahchiev    schedule 09.10.2014