使用@ModelAttribute处理InvalidPropertyException

时间:2018-04-20 14:42:48

标签: spring-mvc spring-boot

我们正在尝试解决与安全扫描相关的问题。它被视为暴露有关基础类的任何信息的漏洞。扫描程序正在向此端点发送无效数据:

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

无效输入看起来像这样,其中"描述"是实体中的有效密钥,但添加" []" 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将POST主体转换为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 个答案:

答案 0 :(得分:1)

对此的解决方案确实是使用ControllerAdvice来包装异常,但您需要根据需要调整响应。

因此,您应该返回一个StringResponseEntity的完整httpStatus,而不是返回bodybody应填充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;
   }
}

答案 1 :(得分:0)

它的结算说明如下

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

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

或者你必须修改请求的发送方式并确保它只发送String类型而不发送List / Map类型 前者是一个更容易的解决方案。 希望它有所帮助:)

相关问题