Enregistrement de sécurité printanier - Renvoyer l’e-mail de vérification

Enregistrement de sécurité Spring - Renvoi d'un e-mail de vérification

1. Vue d'ensemble

Dans ce didacticiel, nous poursuivons lesRegistration with Spring Security series en cours en essayant de renvoyer le lien de vérification à l'utilisateur au cas où il expirerait avant qu'il n'ait la possibilité d'activer son compte.

Voyons d'abord ce qui se passe lorsque l'utilisateurrequests another verification link, au cas où le précédent expirait.

Premièrement, nous allons réinitialiser le jeton existant avec un nouveauexpireDate. Le, nous enverrons à l'utilisateur un nouvel e-mail, avec le nouveau lien / jeton:

@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()));
}

Et l'utilitaire pour créer le message électronique que l'utilisateur obtient -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;
}

Nous devons également modifier la fonctionnalité d'enregistrement existante - en ajoutant de nouvelles informations sur le modèleabout the expiration of the token:

@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. Gestionnaire d'exceptions

La fonctionnalité précédente consiste, sous certaines conditions, à lever des exceptions; ces exceptions doivent être gérées, et nous allons le faire aveca custom exception handler:

@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {

    @Autowired
    private MessageSource messages;

    @ExceptionHandler({ UserNotFoundException.class })
    public ResponseEntity 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 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 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);
    }
}


Notez que:

  • nous avons utilisé l'annotation@ControllerAdvice pour gérer les exceptions dans toute l'application

  • nous avons utilisé un simple objetGenericResponse pour envoyer la réponse:

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. ModifierbadUser.html

Nous allons maintenant modifierbadUser.html en permettant à l'utilisateur d'obtenir un nouveauVerificationToken uniquement si son jeton a expiré:



bad user


error


signup

resend

Notez que nous avons utilisé ici des javascript et JQuery très basiques pour gérer la réponse de "/ user / resendRegistrationToken" et rediriger l'utilisateur en fonction de celle-ci.

5. Conclusion

Dans cet article rapide, nous avons autorisé l'utilisateur àrequest a new verification link to activate their account, au cas où l'ancien expirait.

Lesfull implementation de ce didacticiel se trouvent dansthe github project - il s'agit d'un projet basé sur Eclipse, il devrait donc être facile à importer et à exécuter tel quel.