作者:Eugen Paraschiv
译者:oopsguy.com
1、概述
在本教程中,我们将继续 Spring Security 系列中的注册流程,在用户激活帐户之前重发验证链接给用户。
2、重发验证链接
首先,当用户请求另一个验证链接时,我们需要防上一个验证链接发生过期。
我们将用新的 expireDate 重置现有的令牌,之后向用户发送一封新邮件,并附上新的链接和令牌:
@RequestMapping(value = "/user/resendRegistrationToken", method = RequestMethod.GET)@ResponseBodypublic GenericResponse resendRegistrationToken( HttpServletRequest request, @RequestParam("token") String existingToken) { VerificationToken newToken = userService.generateNewVerificationToken(existingToken); User user = userService.getUser(newToken.getToken()); String appUrl = "http://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath(); SimpleMailMessage email = constructResendVerificationTokenEmail(appUrl, request.getLocale(), newToken, user); mailSender.send(email); return new GenericResponse( messages.getMessage("message.resendToken", null, request.getLocale()));}复制代码
生成用户邮件的工具方法 — constructResendVerificationTokenEmail()
:
private SimpleMailMessage constructResendVerificationTokenEmail (String contextPath, Locale locale, VerificationToken newToken, User user) { String confirmationUrl = contextPath + "/regitrationConfirm.html?token=" + newToken.getToken(); String message = messages.getMessage("message.resendToken", null, locale); SimpleMailMessage email = new SimpleMailMessage(); email.setSubject("Resend Registration Token"); email.setText(message + " rn" + confirmationUrl); email.setFrom(env.getProperty("support.email")); email.setTo(user.getEmail()); return email;}复制代码
我们还需要修改现有的注册功能 — 在模型上添加一些涉及到令牌到期的新逻辑:
@RequestMapping(value = "/regitrationConfirm", method = RequestMethod.GET)public String confirmRegistration( Locale locale, Model model, @RequestParam("token") String token) { VerificationToken verificationToken = userService.getVerificationToken(token); if (verificationToken == null) { String message = messages.getMessage("auth.message.invalidToken", null, locale); model.addAttribute("message", message); return "redirect:/badUser.html?lang=" + locale.getLanguage(); } User user = verificationToken.getUser(); Calendar cal = Calendar.getInstance(); if ((verificationToken.getExpiryDate().getTime() - cal.getTime().getTime()) <= 0) { model.addAttribute("message", messages.getMessage("auth.message.expired", null, locale)); model.addAttribute("expired", true); model.addAttribute("token", token); return "redirect:/badUser.html?lang=" + locale.getLanguage(); } user.setEnabled(true); userService.saveRegisteredUser(user); model.addAttribute("message", messages.getMessage("message.accountVerified", null, locale)); return "redirect:/login.html?lang=" + locale.getLanguage();}复制代码
3、异常处理
以前的功能是在某些情况下抛出异常,这些异常需要处理,我们将使用自定义的异常处理程序来处理这些异常:
@ControllerAdvicepublic class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { @Autowired private MessageSource messages; @ExceptionHandler({ UserNotFoundException.class }) public ResponseEntity
注意:
我们使用 @ControllerAdvice
注解来处理整个应用程序中的异常,并使用一个简单的对象 GenericResponse 来发送响应:
public class GenericResponse { private String message; private String error; public GenericResponse(String message) { super(); this.message = message; } public GenericResponse(String message, String error) { super(); this.message = message; this.error = error; }}复制代码
4、修改 badUser.html
现在我们修改 badUser.html,使用户只有在令牌过期时才能获得新的 VerificationToken
:
bad user error
signup复制代码resend
请注意,我们在这里使用了一些非常简单的 JavaScript 和 JQuery 来处理 /user/resendRegistrationToken 的响应,并根据它重定向用户。
5、结论
在本文中,我们允许用户重新请求一个新的验证链接来激活账户,以防旧账户过期。
本教程的完整实现可以在 项目中找到 — 这是一个基于 Eclipse 的项目,应该很容易导入和运行。