简体   繁体   English

当多部分表单 POST 被 session 超时中断时的异常导致

[英]Exception when multipart form POST interrupted by session timeout results in an

We have Spring security with CAS (I don't think CAS is the problem).我们有 CAS 的 Spring 安全性(我认为 CAS 不是问题)。

The problem is NOT the session timeout , rather how this timeout is handled.问题不是 session 超时,而是如何处理这个超时。

  1. request a form: GET /someform请求表格:GET /someform
  2. fill out a multipart form填写多部分表格
  3. restart the server, or delete JSESSIONID重启服务器,或者删除 JSESSIONID
  4. submit the form: POST /someform (with multipart data)提交表单:POST /someform(带有多部分数据)

  5. user is redirected to the login screen用户被重定向到登录屏幕

  6. after login user is redirected to the form: GET /someform登录后用户被重定向到表单: GET /someform
  7. spring tries to re-post the saved form (I think it's using DefaultSavedRequest) spring 尝试重新发布保存的表单(我认为它使用的是 DefaultSavedRequest)
  8. it tries to call the controller function mapped to: POST /someform, but the request is not multipart它试图调用 controller function 映射到:POST /someform,但请求不是多部分的
  9. we get an exception:我们得到一个例外:

Failed to invoke handler method [public org.springframework.web.servlet.ModelAndView com.xxx.xxx.XXXController.xxxPost(org.springframework.web.multipart.MultipartHttpServletRequest)];调用处理程序方法失败 [public org.springframework.web.servlet.ModelAndView com.xxx.xxx.XXXController.xxxPost(org.springframework.Z2567A5EC9705EB7AC2Request8);HttpServlet8];HttpServlet. nested exception is java.lang.IllegalStateException: Current request is not of type org.springframework.web.multipart.MultipartHttpServletRequest: com.secondmarket.web.UrlLowerCaseFilter$LowerCaseUrlServletRequestWrapper@77fb58b6 nested exception is java.lang.IllegalStateException: Current request is not of type org.springframework.web.multipart.MultipartHttpServletRequest: com.secondmarket.web.UrlLowerCaseFilter$LowerCaseUrlServletRequestWrapper@77fb58b6

This is the code that saves the request to the session upon AccessDeniedException, it's in HttpSessionRequestCache (called by ExceptionTranslationFilter):这是在 AccessDeniedException 时将请求保存到 session 的代码,它位于 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);
        }
    }

}

How can i owverwrite HttpSessionRequestCache or ExceptionTranslationFilter to NOT save the request if it's a multipart request?如果它是多部分请求,我如何编写 HttpSessionRequestCache 或 ExceptionTranslationFilter 以不保存请求?

Solved the problem by modifying controller method signature.通过修改 controller 方法签名解决了该问题。

Previously, MultipartHttpServletRequest was in the method signature.以前,MultipartHttpServletRequest 在方法签名中。 When spring came back from login round trip, it tried calling this method with regular HttpServletRequest, and failed.当 spring 从登录往返返回时,它尝试使用常规 HttpServletRequest 调用此方法,但失败了。

@RequestMapping(value = "/xxx", method = RequestMethod.POST)
public ModelAndView doAmlCheckPost(MultipartHttpServletRequest req) {
    UserInfo currentUserInfo = UserInfo.getCurrentUserInfo(req);

    MultipartFile someFile = req.getFile("someFile");

The fix is to use regular RequestMapping, and pick up the files from the URL.修复方法是使用常规 RequestMapping,并从 URL 中获取文件。 If request is not instanceof MultipartHttpServletRequest - redirect to the GET method, which redisplays the form如果请求不是 MultipartHttpServletRequest 的 instanceof - 重定向到 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";
    }

So the flow is now as follows:所以现在的流程如下:

  1. request a form: GET /someform请求表格:GET /someform
  2. fill out a multipart form填写多部分表格
  3. restart the server, or delete JSESSIONID重启服务器,或者删除 JSESSIONID
  4. submit the form: POST /someform (with multipart data) WHAT HAPPENS HERE IS REQUEST IS SAVED IN THE SESSION, BUT THERE IS NO WAY TO SAVE MULTIPART DATA, IT'S BINARY AND CANNOT BE SERIALIZED提交表格: POST /someform (with multipart data) 这里发生的事情是请求被保存在 SESSION 中,但是没有办法保存多部分数据,它是二进制的,不能被序列化
  5. user is redirected to the login screen用户被重定向到登录屏幕
  6. after login user is redirected to the form: GET /someform登录后用户被重定向到表单: GET /someform
  7. spring tries to re-post the saved form (I think it's using DefaultSavedRequest) SPRING NOW CALLS THE POST METHOD WITH HttpServletRequest, not MultipartHttpServletRequest. spring 尝试重新发布保存的表单(我认为它正在使用 DefaultSavedRequest) We detect that it's not MultipartHttpServletRequest and redirect to the GET page, redisplaying the form to the user我们检测到它不是 MultipartHttpServletRequest 并重定向到 GET 页面,将表单重新显示给用户

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM