Spring mvc Spring 3.1 MVC和安全性:同一页面上的登录和注册表单(多个表单)都被提交

Spring mvc Spring 3.1 MVC和安全性:同一页面上的登录和注册表单(多个表单)都被提交,spring-mvc,spring-security,spring-3,Spring Mvc,Spring Security,Spring 3,我将结合使用Spring(3.1)、SpringMVC(3.1)和SpringSecurity(3.0),并且我将一个JSP页面组合在一起,该页面上有两个表单;一个是要登录的表单,另一个是要注册的表单(即创建新用户) 对于register表单,我使用Spring表单标记,由控制器备份以处理请求,但是对于登录表单,我不需要Spring表单标记,因为我认为不需要它们。我也不需要编写任何控制器来处理表单提交,因为只要请求提交到j\u Spring\u Security\u check,Spring S

我将结合使用Spring(3.1)、SpringMVC(3.1)和SpringSecurity(3.0),并且我将一个JSP页面组合在一起,该页面上有两个表单;一个是要登录的表单,另一个是要注册的表单(即创建新用户)

对于register表单,我使用Spring
表单
标记,由控制器备份以处理请求,但是对于登录表单,我不需要Spring
表单
标记,因为我认为不需要它们。我也不需要编写任何控制器来处理表单提交,因为只要请求提交到
j\u Spring\u Security\u check
,Spring Security就会进行身份验证

注册表单工作正常,但登录表单有问题。似乎当我点击登录表单上的提交按钮时,注册表单也被提交了,或者至少Spring认为我正在尝试提交该表单。以下是JSP:

    <form id="loginform" method="POST" action="<c:url value='j_spring_security_check'/>">
        <label for="existing_email">Email:</label> 
        <input name="j_username" id="existing_email" type="text" value="${SPRING_SECURITY_LAST_USERNAME}" /> 

        <label for="existing_password">Password:</label> 
        <input name="j_password" id="existing_password" type="password" /> 

        <input id="login-form-submit" type="submit" value="Sign in" />
    </form>

    <form:form id="registrationform" modelAttribute="user" method="POST" action="register">
        <form:label path="username" for="email">Email:</form:label> 
        <form:input path="username" name="username" id="email" type="text" /> 
        <form:errors path="username" cssClass="formError" />

        <form:label path="password" for="password">Password:</form:label>
        <form:input path="password" name="password" id="password" type="password" />
        <form:errors path="password" cssClass="formError" />

        <input id="registration-form-submit" type="submit" value="Sign up" />
    </form:form>
我从您忘记在
form:form
中包含modelAttribute属性的情况中认识到这一点,但我当然不想将此表单提交给我的控制器

我觉得我犯了一个错误,或者有一个简单的解决办法。有谁能推荐一种方法来解决这个问题,或者是一种不同的方法吗

以下是控制器方法,用于在需要时处理注册请求:

    @RequestMapping(value = "**/register", method = RequestMethod.POST)
    public String registerUser(@ModelAttribute("user") @Validated User user, BindingResult errors, ModelMap model) {
        if (errors.hasErrors()) {
            return "registration";
        }
        // Other stuff then...
        return "profile"
    }

我认为问题特别是当登录失败,同一个页面被提供时,尽管在不同的URL路径上,因此通过不同的控制器方法。因此,我最初的怀疑是,两份表格都提交了,这可能有点像是在转移视线,尽管我仍然不完全了解发生了什么,这可能与此有关。在任何情况下,这就是为我纠正问题的原因:

我有一个控制器方法,最初看起来像这样:

@RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(ModelMap model) {
    model.addAttribute("error", "true");
    return "registration";
}
在Spring安全上下文中,我指定
/loginfailed
作为默认情况下登录尝试失败时的路径。这就是似乎需要用户对象的地方,因此,如果我按如下方式更改签名,则一切正常:

@RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(@ModelAttribute("user") User user, BindingResult errors, ModelMap model) {
    model.addAttribute("error", "true");
    return "registration";
}

欢迎其他人提供任何评论/澄清。

我认为问题特别是当登录失败并且提供相同页面时,尽管是在不同的URL路径上,因此通过不同的控制器方法。因此,我最初的怀疑是,两份表格都提交了,这可能有点像是在转移视线,尽管我仍然不完全了解发生了什么,这可能与此有关。在任何情况下,这就是为我纠正问题的原因:

我有一个控制器方法,最初看起来像这样:

@RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(ModelMap model) {
    model.addAttribute("error", "true");
    return "registration";
}
在Spring安全上下文中,我指定
/loginfailed
作为默认情况下登录尝试失败时的路径。这就是似乎需要用户对象的地方,因此,如果我按如下方式更改签名,则一切正常:

@RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(@ModelAttribute("user") User user, BindingResult errors, ModelMap model) {
    model.addAttribute("error", "true");
    return "registration";
}
欢迎其他人提供任何意见/澄清。

如果您在表单标记中使用“user”modelAttribute,则必须提供名为“user”的非空请求属性

在请求属性中添加该属性的一种方法是您在上面的答案中所做的操作。其他途径包括:

(1) 加载项模型映射:

    @RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(ModelMap model) {
    model.addAttribute("user", new User());
    model.addAttribute("error", "true");
    return "registration";
}  
(2) 外接程序请求范围(使用WebRequest或HttpServletRequest):

(3) 在方法上使用@ModelAttribute:

    @ModelAttribute("user")
public User user() {
    return new User();
}  
另请参阅及

还要注意,您不必使用type属性。请参阅和。

如果在表单标记中使用“user”modelAttribute,则必须存在名为“user”的非空请求属性

在请求属性中添加该属性的一种方法是您在上面的答案中所做的操作。其他途径包括:

(1) 加载项模型映射:

    @RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(ModelMap model) {
    model.addAttribute("user", new User());
    model.addAttribute("error", "true");
    return "registration";
}  
(2) 外接程序请求范围(使用WebRequest或HttpServletRequest):

(3) 在方法上使用@ModelAttribute:

    @ModelAttribute("user")
public User user() {
    return new User();
}  
另请参阅及


还要注意,您不必使用type属性。请参阅和。

在成功/不成功登录后,您将在哪里重定向用户?成功登录将提供不同的jsp页面,而失败登录将提供相同的页面,即registration.jsp。实际上,这给了我一个线索,问题似乎是当登录失败时,我重定向到相同的jsp,尽管通过不同的控制器方法。我将自己添加一个答案。在成功/不成功登录后,您在哪里重定向用户?成功登录会提供不同的jsp页面,但失败登录会提供相同的页面,即registration.jsp。实际上,这给了我一个线索,问题似乎是当登录失败时,我重定向到相同的jsp,尽管通过不同的控制器方法。我将自己添加一个答案。如中所述,“方法参数上的@ModelAttribute指示应从模型中检索参数。如果模型中不存在参数,则应首先实例化该参数,然后将其添加到模型中。”因为您没有绑定请求参数,您的解决方案相当于在模型中添加新的用户对象。此外,签名中不需要BindingResult。如中所述,“方法参数上的@ModelAttribute指示应从模型中检索参数。如果模型中不存在参数,则应首先实例化参数,然后将其添加到模型中。”因为您没有绑定请求参数,您的解决方案相当于在模型中添加新的用户对象。此外,BindingResult不需要in签名。