代码之家  ›  专栏  ›  技术社区  ›  Chuck M

使用@ModelAttribute处理InvalidPropertyException

  •  3
  • Chuck M  · 技术社区  · 7 年前

    我们正在尝试解决与安全扫描相关的问题。暴露有关底层类的任何信息被认为是一个漏洞。扫描仪正在将无效数据发送到此终结点:

    @PostMapping(value = "/accountKey", params = "update")
    public String accountKeyUpdate(@Valid @ModelAttribute("accountKeyForm") AccountKeyForm key, BindingResult bindingResult, Authentication authentication)
    

    无效输入如下所示,其中“description”是实体中的有效键,但在POST数据的属性名称末尾添加“[]”会导致解析错误:

    description[]:
    

    服务器返回以下内容:

    {
        "timestamp": "2018-04-20T14:28:36.653Z",
        "status": 500,
        "error": "Internal Server Error",
        "message": "Invalid property 'description[]' of bean class 
    [com.imsweb.seerapi.account.AccountKeyForm]: Property referenced in indexed property path 'description[]' is neither an array nor a List nor a Map; returned value was []",
    "path": "/accountKey/"
    }
    

    以下是日志中显示的内容:

    org.springframework.beans.InvalidPropertyException: Invalid property 'description[]' of bean class [com.imsweb.seerapi.account.AccountKeyForm]: Property referenced in indexed property path 'description[]' is neither an array nor a List nor a Map; returned value was []
        at org.springframework.beans.AbstractNestablePropertyAccessor.processKeyedProperty(AbstractNestablePropertyAccessor.java:375) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:275) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:266) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:97) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:839) ~[spring-context-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.validation.DataBinder.doBind(DataBinder.java:735) ~[spring-context-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:197) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:107) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.bindRequestParameters(ServletModelAttributeMethodProcessor.java:157) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:153) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:124) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:131) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:877) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    

    问题是我找不到一种方法来优雅地处理无效的输入。当@ModelAttribute将帖子正文转换为AccountKeyForm时,似乎会发生这种情况。那是在它进入控制器方法之前。我更愿意处理错误并将其转发到另一页。或者,如果消息中说

    "message": "Invalid property 'description[]'"
    

    那也可以。

    更新时间:

    我可以使用@ExceptionHandler捕获特定异常:

    @ControllerAdvice
    public class WebControllerAdvice {
    
        @ExceptionHandler(InvalidPropertyException.class)
        public String handleBadPropertyException() {
            return "error";
        }
    }
    

    这意味着我只会得到一条普通的信息。这将不会出现其他类型的异常,这些异常可能会从裂缝中消失。有更好的方法吗?

    更新时间:

    这是实体类。它是一个具有两个属性的简单bean。

    public class AccountKeyForm {
    
        private String _apiKey;
        private String _description;
    
        public AccountKeyForm() {
        }
    
        public AccountKeyForm(String apiKey) {
            _apiKey = apiKey;
        }
    
        public AccountKeyForm(String apiKey, String description) {
            _apiKey = apiKey;
            _description = description;
        }
    
        public String getApiKey() {
            return _apiKey;
        }
    
        public void setApiKey(String apiKey) {
            _apiKey = apiKey;
        }
    
        @Size(max = 256)
        public String getDescription() {
            return _description;
        }
    
        public void setDescription(String description) {
            _description = description;
        }
    }
    
    2 回复  |  直到 7 年前
        1
  •  1
  •   Pedro Tavares    7 年前

    解决方法确实是使用 ControllerAdvice ,但您需要根据需要调整响应。

    因此,不是返回 String ,您应该返回完整的 ResponseEntity 使用 httpStatus body 这个 身体 应填充 ErrorResponse 如果您有类似的内容和自定义消息,您可以在其中定义域错误代码。

    类似下面的代码应该可以工作。

    @ControllerAdvice
    public class WebControllerAdvice {
    
        @ExceptionHandler(InvalidPropertyException.class)
        public ResponseEntity<ErrorResponse> handle(InvalidPropertyException e) {
            return ResponseEntity.status(httpStatus)
                .body(new ErrorResponse(errorCode, message));
        }
    }
    
    public class ErrorResponse {
    
       private final String code;
       private final String message;
    
       public ErrorResponse(String code, String message) {
           this.code = code;
           this.message = message;
       }
    }
    
        2
  •  0
  •   rohit thomas    7 年前

    下面是清白的说法

    Property referenced in indexed property path 'description[]' is neither an array nor a List nor a Map; returned value was []

    这意味着从请求发送的描述字段的类型为array/List/map,因此,您必须相应地更改模型类AccountKeyForm描述 从…起 private String _description; private List<String> _description; private Map<String> _description; 您需要确定发送的集合类型:)

    或者,您必须修改请求的发送方式,并确保它只发送字符串类型,而不是列表/映射类型 前者更容易解决。 希望有帮助:)