在Spring中使用setAllowedFields()方法

时间:2013-02-22 18:43:22

标签: spring spring-mvc spring-3 databinder propertyeditor

我正在使用Spring 3.2.0。我已经为一些基本需求注册了一些自定义属性编辑器,如下所示。

import editors.DateTimeEditor;
import editors.StrictNumberFormatEditor;
import java.math.RoundingMode;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import org.joda.time.DateTime;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.beans.propertyeditors.URLEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.context.request.WebRequest;

@ControllerAdvice
public final class GlobalDataBinder 
{
    @InitBinder
    public void initBinder(WebDataBinder binder, WebRequest request)
    {
        binder.setIgnoreInvalidFields(true);
        binder.setIgnoreUnknownFields(true);
        //binder.setAllowedFields(someArray);
        NumberFormat numberFormat=DecimalFormat.getInstance();
        numberFormat.setGroupingUsed(false);
        numberFormat.setMaximumFractionDigits(2);
        numberFormat.setRoundingMode(RoundingMode.HALF_UP);

        binder.registerCustomEditor(DateTime.class, new DateTimeEditor("MM/dd/yyyy HH:mm:ss", true));
        binder.registerCustomEditor(Double.class, new StrictNumberFormatEditor(Double.class, numberFormat, true));
        binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
        binder.registerCustomEditor(URL.class, new URLEditor());
    } 
}

到目前为止,我已经注册了这么多编辑。其中两个DateTimeEditorStrictNumberFormatEditor已通过覆盖相应方法进行自定义,以满足数字格式和Joda-Time的自定义需求。

由于我使用的是Spring 3.2.0,我可以利用@ControllerAdvice

Spring建议使用setAllowedFields()方法列出一组允许的字段,以便恶意用户无法将值注入绑定对象。

来自docs关于DataBinder

  

允许将属性值设置到目标对象上的Binder,   包括对验证和绑定结果分析的支持。该   绑定过程可以通过指定允许的字段来定制,   必填字段,自定义编辑器等

     

请注意,未能设置可能会对安全产生影响   一系列允许的字段。在HTTP表单POST数据的情况下   例如,恶意客户端可以尝试通过破坏应用程序   提供不存在的字段或属性的值   形成。在某些情况下,这可能导致非法数据被设置   命令对象或其嵌套对象。因此,它非常强烈   建议在DataBinder上指定allowedFields属性。


我有一个很大的应用程序,显然有数千个字段。使用setAllowedFields()指定和列出所有这些是一项繁琐的工作。另外,不知怎的,我需要记住它们。

根据需要更改网页以删除某些字段或添加其他字段需要修改setAllowedFields()方法的参数值以反映这些更改。

还有其他选择吗?

4 个答案:

答案 0 :(得分:4)

您可以使用setAllowedFields()黑名单,而不是使用setDisallowedFields()白名单。例如,来自petclinic样本申请:

@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
    dataBinder.setDisallowedFields("id");
}

从纯粹的安全角度来看,白名单比黑名单更受欢迎,但它可能有助于减轻一些负担。

答案 1 :(得分:2)

在Web层中直接使用实体对象时,setAllowedFields()非常方便。或者,可以使用专用数据传输对象(DTO),在服务层中构造实体对象。工厂不仅可以重复使用,而且还可以在网络环境之外使用,例如,用于异步消息。此外,DTO继承不必遵循实体继承,因此您可以根据用例的需要自由设计DTO层次结构。

答案 2 :(得分:0)

来自http://static.springsource.org/spring-webflow/docs/2.0.x/reference/htmlsingle/spring-webflow-reference.html#view-model

4.9。明确指定绑定

使用binder元素配置视图可用的确切模型绑定集。这在Spring MVC环境中特别有用,用于限制每个视图的“允许字段”集。

<view-state id="enterBookingDetails" model="booking">
    <binder>
        <binding property="creditCard" />
        <binding property="creditCardName" />
        <binding property="creditCardExpiryMonth" />
        <binding property="creditCardExpiryYear" />
    </binder>
    <transition on="proceed" to="reviewBooking" />
    <transition on="cancel" to="cancel" bind="false" />
</view-state>

如果未指定binder元素,则模型的所有公共属性都有资格通过视图进行绑定。指定了binder元素后,只允许显式配置的绑定。

每个绑定还可以应用转换器来格式化模型属性值,以便以自定义方式显示。如果未指定转换器,则将使用模型属性类型的默认转换器。

<view-state id="enterBookingDetails" model="booking">
    <binder>
        <binding property="checkinDate" converter="shortDate" />
        <binding property="checkoutDate" converter="shortDate" />    
        <binding property="creditCard" />
        <binding property="creditCardName" />
        <binding property="creditCardExpiryMonth" />
        <binding property="creditCardExpiryYear" />
    </binder>
    <transition on="proceed" to="reviewBooking" />
    <transition on="cancel" to="cancel" bind="false" />
</view-state>

在上面的示例中,shortDate转换器绑定到checkinDate和checkoutDate属性。自定义转换器可以在应用程序的ConversionService中注册。

如果用户提供的值在表单回发时为null,则每个绑定也可能会应用必需的检查,这将生成验证错误:

<view-state id="enterBookingDetails" model="booking">
    <binder>
        <binding property="checkinDate" converter="shortDate" required="true" />
        <binding property="checkoutDate" converter="shortDate" required="true" />
        <binding property="creditCard" required="true" />
        <binding property="creditCardName" required="true" />
        <binding property="creditCardExpiryMonth" required="true" />
        <binding property="creditCardExpiryYear" required="true" />
    </binder>
    <transition on="proceed" to="reviewBooking">
    <transition on="cancel" to="bookingCancelled" bind="false" />
</view-state>

在上面的示例中,所有绑定都是必需的。如果绑定了一个或多个空白输入值,则将生成验证错误,并且视图将使用这些错误重新呈现。

答案 3 :(得分:0)

一种将活页夹与DTO结合使用的解决方案(例如,companydata),以防大多数表单输入值如果为空则应转换为null,但是需要添加一些例外(setDisallowedFields对我不起作用)。

@InitBinder()
public void initBinder(WebDataBinder binder) {
    binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}

@InitBinder
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
    binder.registerCustomEditor(String.class, "companydata.companyName", new StringTrimmerEditor(false));
    binder.registerCustomEditor(String.class, "companydata.companyNumber", new StringTrimmerEditor(false));
}