@InitBinder阻止从JSP更新对象

时间:2014-06-12 18:51:48

标签: jsp spring-mvc jpa data-binding

我理解@InitBinder用于安全原因,但它引起了各种各样的问题。

我有一个UserController,其更新方法如下。

    @Secured(value={"ROLE_ADMIN"})
    @Transactional
    @RequestMapping(value="/user/{id}", method=RequestMethod.PUT)
    public String userUpdate(User user, BindingResult userBinding, Model model, @PathVariable long id) {

    if (userBinding.hasErrors()) {
        return (String.format("user/{%s}/edit", String.valueOf(user.getId())));
    }

    try {
        userService.updateUser(user);
    }
    catch (Exception e) {
        logger.error("Unable to update user", e);
    }

    return "redirect:/user";
}

我还有我的UserController。

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

我的处理创建和更新的JSP在下面。

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>

<div class="container">
    <div class="row">
        <div class="col-xs-12">
            <spring:bind path="user.*">
                <c:if test="${status.errors.errorCount > 0}">
                    <div class="alert alert-danger">
                        <p>Error: unable to save, please check the errors below</p>
                    </div>
                </c:if>
            </spring:bind>
        </div>
    </div>
    <div class="row">
        <div class="col-xs-12 col-sm-8 col-md-6">
            <h3>User - Add</h3>
            <br>

            <c:choose>
                <c:when test="${user.id > 0}">
                    <c:set var="formMethod" value="PUT" />
                    <c:url var="formAction" value="/user/${user.id}" />
                </c:when>
                <c:otherwise>
                    <c:set var="formMethod" value="POST" />
                    <c:url var="formAction" value="/user" />
                </c:otherwise>
            </c:choose>

            <sf:form method="${formMethod}" action="${formAction}" commandName="user">
                <spring:bind path="user.id">
                    <sf:hidden path="${status.expression}" id="user-id" />
                </spring:bind>
                <spring:bind path="user.firstName">
                    <div class="form-group">
                        <label for="first-name">First Name</label>
                        <sf:input path="${status.expression}" id="first-name" class="form-control" placeholder="First Name" />
                        <sf:errors path="${status.expression}" cssClass="error-message"></sf:errors>
                    </div>
                </spring:bind>
                <spring:bind path="user.lastName">
                    <div class="form-group">
                        <label for="last-name">Last Name</label>
                        <sf:input path="${status.expression}" id="last-name" class="form-control" placeholder="Last Name" />
                        <sf:errors path="${status.expression}" cssClass="error-message"></sf:errors>
                    </div>
                </spring:bind>
                <spring:bind path="user.email">
                    <div class="form-group">
                        <label for="email">Email</label>
                        <sf:input path="${status.expression}" id="email" class="form-control" placeholder="Email" />
                        <sf:errors path="${status.expression}" cssClass="error-message"></sf:errors>
                    </div>
                </spring:bind>
                <spring:bind path="user.username">
                    <div class="form-group">
                        <label for="user-name">Username</label>
                        <sf:input path="${status.expression}" id="user-name" class="form-control" placeholder="Username" />
                        <sf:errors path="${status.expression}" cssClass="error-message"></sf:errors>
                    </div>
                </spring:bind>
                <spring:bind path="user.password">
                    <div class="form-group">
                        <label for="password">Password</label>
                        <sf:password path="${status.expression}" id="password" class="form-control" placeholder="" />
                        <sf:errors path="${status.expression}" cssClass="error-message"></sf:errors>
                    </div>
                </spring:bind>
                <div class="form-group">
                    <label for="confirm-password">Confirm Password</label>
                    <input type="password" name="password-confirm" id="confirm-password" class="form-control" placeholder="" />
                </div>
                <spring:bind path="user.roleId">
                    <div class="form-group">
                        <label for="role">Role</label>
                        <sf:select path="${status.expression}" id="role" class="form-control" >
                            <sf:options items="${roles}" itemLabel="name" itemValue="id"/>
                        </sf:select>
                        <sf:errors path="${status.expression}" cssClass="error-message"></sf:errors>
                    </div>
                </spring:bind>
                <button type="submit" class="btn btn-default">Save</button>
                <button type="button" class="btn btn-default">Cancel</button>
            </sf:form>
        </div>
    </div>
</div>

对userService.update(user)的调用是调用JPA merge方法。它失败了,因为它试图插入一个包含数据库中已有的唯一约束的新记录。毋庸置疑,经过几个小时的挖掘代码,互联网和堆栈跟踪,我意识到从JSP回来的id是空的。一旦我注释掉了@InitBinder方法,一切都开始正常了。这让我想到了一个真正的问题,我是否因为安全原因需要@InitBinder,如果是这样,我如何处理我刚才描述的问题呢?

0 个答案:

没有答案