Spring安全性,更改密码后绕过登录页面

时间:2012-11-03 16:18:49

标签: spring model-view-controller spring-security

我对Java / Spring / MVC比较陌生。我希望有人可以对此有所启发,因为这个问题即将毁掉又一个周末但没有得到解决。

目前我正在开展一个项目,实施一些RFC。每个RFC都有自己的“挑战”,从更改hibernate查询和存储过程到轻微的文本更改,以及向表单添加额外的字段。

我现在面临的问题(我认为)与Spring安全有关。

现状:
要登录该应用程序,用户将通过登录页面(/user/login.jsp)显示。输入用户名和密码后,用户将被发送到欢迎页面(/welcome/hello.jsp)。

如果用户忘记了密码,他们会使用一个链接,该链接会发送一封电子邮件,提供指向页面的链接(/ welcome / newPassword?code = xxx),可以输入新密码。输入提交按钮将进行一些验证,将密码保存在数据库中并在页面上显示“密码已更改”消息。 要进入该应用程序,用户现在必须使用新密码登录。

客户想要什么: 提交新密码后,用户应自动使用新密码登录并重定向到/welcome/hello.jsp

我在网上搜索过,但找不到我正在寻找的情景(或者可能没有认出来!)。

我认为可以做到这一点:

我在WelcomeController中有这个方法,它目前处理新密码:

@RequestMapping(method = RequestMethod.POST)
public void newPassword(Model model, HttpSession httpSession, ModelAttribute(PASSWORD) Passwords password, BindingResult result) {
    logger.debug("Posting password for new password");
    ScreenMessage message = null;

    //
    try {
        // errors from initBinder - back to page
        if (result.hasErrors()) {
            return;
        }

        // Validate input: on error go back to form
        passwordValidator.validate(password, result);
        if (result.hasErrors()) {
            return;
        }

        // Save password
        passwordService.createNewOwnPassword(result, password);
        if (result.hasErrors()) {
            return;
        }

        // No errors
        message = new ScreenMessage();
        message.setText(CHANGED);
        message.setArg(THIS_PASSWORD, 0);
        model.addAttribute(MESSAGE, message);
        httpSession.setAttribute(ACTION_READ, Boolean.TRUE);

        // Errors are fatal.
    } catch (Exception e) {
        logger.error("ERROR-CHANGE-password for user: " + password.getUser().getLoginName(), e);
        result.reject(  ERROR_FATAL, new Object[] { password}, ERROR_FATAL);
    } finally {
        model.addAttribute(PASSWORD, password);
    }
}

我认为我可以简单地更改此方法,让它返回ModelAndView并使用重定向:

ModelAndView mav = new ModelAndView("redirect:/welcome/hello", (ModelMap) model);
        return mav; 

但是:它一直把我发送到/ user / login,这正是我不想去的页面......

可以使用的额外信息:

据我所知,应用程序正在使用Spring 2.5。

(我希望相关)我的security-applicationContext.xml的一部分:

    <!--  always-use-default-target="true" -->
    <security:form-login login-page="/dyn/user/login" 
        login-processing-url="/dyn/user/j_spring_security_check"
        default-target-url="/dyn/welcome/hello" 
        always-use-default-target="true"
        authentication-failure-handler-ref="exceptionTranslationRouting" />

    <security:access-denied-handler error-page="/dyn/welcome/hello" />

    <security:logout logout-success-url="/dyn/user/logout" invalidate-session="true" />

我的想法是重定向到/ welcome / hello太简单了还是我只是错过了一些小东西?

1 个答案:

答案 0 :(得分:1)

首先,您最好将逻辑从Web控制器(我不喜欢密码验证)转移到专用于密码更改的组件。这将允许您在逻辑上分离应用程序的各个部分。可能过滤? (稍后)或特殊服务?

其次,看一下Spring Security的源代码。根据我的经验,我可以告诉您,只有了解其体系结构(尤其是过滤器链),才能实现Spring Security中的任何自定义。我建议你看看课程AbstractAuthenticationProcessingFilter。 当用户在您的应用程序中提供用户名和密码时,它负责对用户进行身份验证。看一下方法AbstractAuthenticationProcessingFilter.successfulAuthentication

该方法的这一行设置了使用户登录的安全上下文:

 SecurityContextHolder.getContext().setAuthentication(authResult);

参考authResult的类型为Authentication。它是由例如UsernamePasswordAuthenticationToken实现的接口。看看UsernamePasswordAuthenticationFilter.attemptAuthentication方法,例如如何构造这样的对象。

回到过滤解决方案: 我个人会想到实现我自己的扩展AbstractAuthenticationProcessingFilter的过滤器。它将负责密码更改。这样,您就不必考虑成功验证时会话更改等问题。你只需要在XML中注入它。

总结一下,

建议查看的类:

  • AbstractAuthenticationProcessingFilter
  • UsernamePasswordAuthenticationToken
  • UsernamePasswordAuthenticationFilter

您应该阅读Spring Security Documentation,特别是有关体系结构,过滤器链及其在验证用户身份中的作用的部分。

http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#overall-architecture