www.baeldung.com/spring-secu…javascript
做者:Eugen Paraschivhtml
譯者:oopsguy.comjava
在本教程中,咱們將繼續 Spring Security 系列中的註冊流程,在用戶激活賬戶以前重發驗證連接給用戶。jquery
首先,當用戶請求另外一個驗證連接時,咱們須要防上一個驗證連接發生過時。git
咱們將用新的 expireDate 重置現有的令牌,以後向用戶發送一封新郵件,並附上新的連接和令牌:github
@RequestMapping(value = "/user/resendRegistrationToken", method = RequestMethod.GET)
@ResponseBody
public 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()
:spring
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;
}
複製代碼
咱們還須要修改現有的註冊功能 — 在模型上添加一些涉及到令牌到期的新邏輯:app
@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();
}
複製代碼
之前的功能是在某些狀況下拋出異常,這些異常須要處理,咱們將使用自定義的異常處理程序來處理這些異常:工具
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@Autowired
private MessageSource messages;
@ExceptionHandler({ UserNotFoundException.class })
public ResponseEntity<Object> handleUserNotFound(RuntimeException ex, WebRequest request) {
logger.error("404 Status Code", ex);
GenericResponse bodyOfResponse = new GenericResponse(
messages.getMessage("message.userNotFound", null, request.getLocale()), "UserNotFound");
return handleExceptionInternal(
ex, bodyOfResponse, new HttpHeaders(), HttpStatus.NOT_FOUND, request);
}
@ExceptionHandler({ MailAuthenticationException.class })
public ResponseEntity<Object> handleMail(RuntimeException ex, WebRequest request) {
logger.error("500 Status Code", ex);
GenericResponse bodyOfResponse = new GenericResponse(
messages.getMessage(
"message.email.config.error", null, request.getLocale()), "MailError");
return handleExceptionInternal(
ex, bodyOfResponse, new HttpHeaders(), HttpStatus.NOT_FOUND, request);
}
@ExceptionHandler({ Exception.class })
public ResponseEntity<Object> handleInternal(RuntimeException ex, WebRequest request) {
logger.error("500 Status Code", ex);
GenericResponse bodyOfResponse = new GenericResponse(
messages.getMessage(
"message.error", null, request.getLocale()), "InternalError");
return handleExceptionInternal(
ex, bodyOfResponse, new HttpHeaders(), HttpStatus.NOT_FOUND, request);
}
}
複製代碼
注意:oop
咱們使用 @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;
}
}
複製代碼
如今咱們修改 badUser.html,使用戶只有在令牌過時時才能得到新的 VerificationToken
:
<html>
<head>
<title th:text="#{label.badUser.title}">bad user</title>
</head>
<body>
<h1 th:text="${param.message[0]}">error</h1>
<br>
<a th:href="@{/user/registration}" th:text="#{label.form.loginSignUp}">
signup</a>
<div th:if="${param.expired[0]}">
<h1 th:text="#{label.form.resendRegistrationToken}">resend</h1>
<button onclick="resendToken()" th:text="#{label.form.resendRegistrationToken}">resend</button>
<script src="jquery.min.js"></script>
<script type="text/javascript"> var serverContext = [[@{/}]]; function resendToken(){ $.get(serverContext + "user/resendRegistrationToken?token=" + token, function(data){ window.location.href = serverContext +"login.html?message=" + data.message; }) .fail(function(data) { if(data.responseJSON.error.indexOf("MailError") > -1) { window.location.href = serverContext + "emailError.html"; } else { window.location.href = serverContext + "login.html?message=" + data.responseJSON.message; } }); } </script>
</div>
</body>
</html>
複製代碼
請注意,咱們在這裏使用了一些很是簡單的 JavaScript 和 JQuery 來處理 /user/resendRegistrationToken 的響應,並根據它重定向用戶。
在本文中,咱們容許用戶從新請求一個新的驗證連接來激活帳戶,以防舊帳戶過時。
本教程的完整實現能夠在 github 項目中找到 — 這是一個基於 Eclipse 的項目,應該很容易導入和運行。