#java #spring #spring-security #session-timeout #multipartform-data
#java #spring #spring-безопасность #тайм-аут сеанса #составная форма-данные
Вопрос:
У нас есть Spring security с CAS (я не думаю, что CAS является проблемой).
Проблема заключается НЕ в тайм-ауте сеанса, а в том, как этот тайм-аут обрабатывается.
- запрос формы: GET /someform
- заполните составную форму
- перезапустите сервер или удалите JSESSIONID
-
отправьте форму: POST / someform (с составными данными)
-
пользователь перенаправляется на экран входа в систему
- после входа в систему пользователь перенаправляется на форму: GET / someform
- spring пытается повторно опубликовать сохраненную форму (я думаю, что она использует DefaultSavedRequest)
- он пытается вызвать функцию контроллера, сопоставленную с: POST / someform, но запрос не является составным
- мы получаем исключение:
Не удалось вызвать метод обработчика [public org.springframework.web.servlet.ModelAndView com.xxx.xxx.XXXController.xxxPost(org.springframework.web.multipart.MultipartHttpServletRequest)]; вложенным исключением является java.lang.Исключение IllegalStateException: Текущий запрос не относится к типу org.springframework.web.multipart.MultipartHttpServletRequest: com.secondmarket.web.UrlLowerCaseFilter$LowerCaseUrlServletRequestWrapper@77fb58b6
Это код, который сохраняет запрос в сеанс при AccessDeniedException, он находится в HttpSessionRequestCache (вызывается ExceptionTranslationFilter):
public void saveRequest(HttpServletRequest request, HttpServletResponse response) {
if (!justUseSavedRequestOnGet || "GET".equals(request.getMethod())) {
DefaultSavedRequest savedRequest = new DefaultSavedRequest(request, portResolver);
if (createSessionAllowed || request.getSession(false) != null) {
// Store the HTTP request itself. Used by AbstractAuthenticationProcessingFilter
// for redirection after successful authentication (SEC-29)
request.getSession().setAttribute(WebAttributes.SAVED_REQUEST, savedRequest);
logger.debug("DefaultSavedRequest added to Session: " savedRequest);
}
}
}
Как я могу перезаписать HttpSessionRequestCache или ExceptionTranslationFilter, чтобы НЕ сохранять запрос, если это составной запрос?
Ответ №1:
Решена проблема путем изменения подписи метода контроллера.
Ранее MultipartHttpServletRequest был в сигнатуре метода. Когда spring вернулся после обхода входа в систему, он попытался вызвать этот метод с помощью обычного HttpServletRequest и потерпел неудачу.
@RequestMapping(value = "/xxx", method = RequestMethod.POST)
public ModelAndView doAmlCheckPost(MultipartHttpServletRequest req) {
UserInfo currentUserInfo = UserInfo.getCurrentUserInfo(req);
MultipartFile someFile = req.getFile("someFile");
Исправление заключается в использовании обычного сопоставления запросов и получении файлов по URL. Если запрос не является экземпляром MultipartHttpServletRequest — перенаправление на метод GET, который повторно отображает форму
@RequestMapping(value = "/xxx", method = RequestMethod.POST)
public ModelAndView doAmlCheckMultipartPost(HttpServletRequest req, @RequestParam(value = "someFile", required = false) MultipartFile someFile) {
if(!(req instanceof MultipartHttpServletRequest)){
return "redirect:/xxx";
}
Таким образом, поток теперь выглядит следующим образом:
- запрос формы: GET /someform
- заполните составную форму
- перезапустите сервер или удалите JSESSIONID
- отправьте форму: POST / someform (с составными данными), ЧТО ЗДЕСЬ ПРОИСХОДИТ, ЗАПРОС СОХРАНЯЕТСЯ В СЕАНСЕ, НО НЕТ СПОСОБА СОХРАНИТЬ СОСТАВНЫЕ ДАННЫЕ, ОНИ ДВОИЧНЫЕ И НЕ МОГУТ БЫТЬ СЕРИАЛИЗОВАНЫ
- пользователь перенаправляется на экран входа в систему
- после входа в систему пользователь перенаправляется на форму: GET / someform
- spring пытается повторно опубликовать сохраненную форму (я думаю, что она использует DefaultSavedRequest) SPRING ТЕПЕРЬ ВЫЗЫВАЕТ МЕТОД POST С HttpServletRequest, а не MultipartHttpServletRequest. Мы обнаруживаем, что это не MultipartHttpServletRequest и перенаправляем на страницу ПОЛУЧЕНИЯ, повторно отображая форму пользователю