我对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太简单了还是我只是错过了一些小东西?
答案 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,特别是有关体系结构,过滤器链及其在验证用户身份中的作用的部分。