Registrering - Aktiver en ny konto via e-post

Denne artikkelen er en del av en serie: • Opplæringsveiledning for vårsikkerhetsregistrering

• Registreringsprosessen med vårsikkerhet

• Registrering - Aktiver en ny konto via e-post (nåværende artikkel) • Vårsikkerhetsregistrering - Send bekreftelses-e-post på nytt

• Registrering med vårsikkerhet - passordkoding

• Registrerings-API-et blir RESTful

• Spring Security - Tilbakestill passordet ditt

• Registrering - Passordstyrke og regler

• Oppdatere passordet ditt

1. Oversikt

Denne artikkelen fortsetter den pågående Registrering hos Spring Security serie med en av de manglende delene av registreringsprosessen - bekrefte brukerens e-post for å bekrefte kontoen.

Registreringsbekreftelsesmekanismen tvinger brukeren til å svare på en “Bekreft registrering”E-post sendt etter vellykket registrering for å bekrefte e-postadressen og aktivere deres konto. Brukeren gjør dette ved å klikke på en unik aktiveringskobling sendt til dem via e-post.

Etter denne logikken vil ikke en nyregistrert bruker kunne logge på systemet før denne prosessen er fullført.

2. En bekreftelsestoken

Vi vil bruke et enkelt bekreftelsestoken som nøkkelgjenstanden som en bruker blir verifisert gjennom.

2.1. De VerificationToken Enhet

De VerificationToken enheten må oppfylle følgende kriterier:

  1. Det må lenke tilbake til Bruker (via et ensrettet forhold)
  2. Det blir opprettet rett etter registrering
  3. Det vil utløper innen 24 timer etter opprettelsen
  4. Har en unik, tilfeldig generert verdi

Krav 2 og 3 er en del av registreringslogikken. De to andre er implementert på en enkel måte VerificationToken enhet som den i eksempel 2.1:

Eksempel 2.1.

@Entity public class VerificationToken {private static final int EXPIRATION = 60 * 24; @Id @GeneratedValue (strategi = GenerationType.AUTO) privat Lang id; private String token; @OneToOne (targetEntity = User.class, fetch = FetchType.EAGER) @JoinColumn (nullable = false, name = "user_id") privat brukerbruker; privat dato utløpsdato; privat dato calcExExyDate (int expiryTimeInMinutes) {Kalender cal = Calendar.getInstance (); cal.setTime (ny tidsstempel (cal.getTime (). getTime ())); cal.add (Calendar.MINUTE, expiryTimeInMinutes); returner ny dato (cal.getTime (). getTime ()); } // standardkonstruktører, getters og setters}

Legg merke til nullable = false på brukeren for å sikre dataintegritet og konsistens i VerificationToken <->Bruker assosiasjon.

2.2. Legg til aktivert Felt til Bruker

Opprinnelig, når Bruker er registrert, dette aktivert feltet vil bli satt til falsk. Under kontobekreftelsesprosessen - hvis det lykkes - blir det ekte.

La oss starte med å legge til feltet i vårt Bruker enhet:

public class User {... @Column (name = "enabled") private boolean enabled; offentlig bruker () {super (); this.enabled = false; } ...}

Legg merke til hvordan vi også setter standardverdien for dette feltet til falsk.

3. Under kontoregistrering

La oss legge til to ekstra forretningslogikk i brukerregistreringen:

  1. Generer VerificationToken for brukeren og vedvare den
  2. Send ut e-postmeldingen for kontobekreftelse - som inkluderer en bekreftelseskobling med VerificationToken's verdi

3.1. Bruke en vårhendelse til å lage tegnet og sende bekreftelses-e-posten

Disse to ekstra delene av logikken skal ikke utføres av kontrolleren direkte fordi de er "sikkerhet" back-end-oppgaver.

Kontrolleren vil publisere en vår ApplicationEvent for å utløse utførelsen av disse oppgavene. Dette er så enkelt som å injisere ApplicationEventPublisher og deretter bruke den til å publisere fullføringen av registreringen.

Eksempel 3.1. viser denne enkle logikken:

Eksempel 3.1.

@Autowired ApplicationEventPublisher eventPublisher @PostMapping ("/ bruker / registrering") offentlig ModelAndView registerUserAccount (@ModelAttribute ("bruker") @Valid UserDto userDto, HttpServletRequest forespørsel, Feil feil) {prøv {Brukerregistrert = userService.registerNewUserA String appUrl = request.getContextPath (); eventPublisher.publishEvent (nytt OnRegistrationCompleteEvent (registrert, request.getLocale (), appUrl)); } fange (UserAlreadyExistException uaeEx) {ModelAndView mav = ny ModelAndView ("registrering", "bruker", userDto); mav.addObject ("melding", "Det finnes allerede en konto for brukernavnet / e-postadressen."); retur mav; } catch (RuntimeException ex) {return new ModelAndView ("emailError", "user", userDto); } returner ny ModelAndView ("successRegister", "user", userDto); }

En ekstra ting å legge merke til er prøv å fange blokk rundt publiseringen av arrangementet. Denne koden vil vise en feilside når det er et unntak i logikken utført etter publiseringen av hendelsen, som i dette tilfellet er sending av e-posten.

3.2. Arrangementet og lytteren

La oss nå se den faktiske implementeringen av denne nye OnRegistrationCompleteEvent som kontrolleren vår sender ut, så vel som lytteren som skal håndtere det:

Eksempel 3.2.1. - Den OnRegistrationCompleteEvent

offentlig klasse OnRegistrationCompleteEvent utvider ApplicationEvent {private String appUrl; private lokale språk; privat brukerbruker; public OnRegistrationCompleteEvent (User user, Locale locale, String appUrl) {super (user); this.user = bruker; this.locale = sted; this.appUrl = appUrl; } // standard getters and setters}

Eksempel 3.2.2. Registreringslytteren Håndterer OnRegistrationCompleteEvent

@Komponent offentlig klasse RegistrationListener implementerer ApplicationListener {@Autowired privat IUserService-tjeneste; @Autowired private MessageSource-meldinger; @Autowired privat JavaMailSender mailSender; @ Overstyr offentlig tomrom påApplicationEvent (OnRegistrationCompleteEvent event) {this.confirmRegistration (event); } privat tomrom confirmRegistration (OnRegistrationCompleteEvent hendelse) {Bruker bruker = event.getUser (); String token = UUID.randomUUID (). ToString (); service.createVerificationToken (bruker, token); String recipientAddress = user.getEmail (); Strengemne = "Registreringsbekreftelse"; StrengbekreftelseUrl = event.getAppUrl () + "/regitrationConfirm.html?token=" + token; Strengmelding = messages.getMessage ("message.regSucc", null, event.getLocale ()); SimpleMailMessage e-post = ny SimpleMailMessage (); email.setTo (recipientAddress); email.setSubject (emne); email.setText (melding + "\ r \ n" + "// localhost: 8080" + confirmUrl); mailSender.send (e-post); }}

Her, den bekreft Registrering metoden vil motta OnRegistrationCompleteEvent, trekk ut alt det nødvendige Bruker informasjon fra den, opprett bekreftelsestokenet, fortsett den, og send den som en parameter i “Bekreft registrering”Lenke.

Som nevnt ovenfor, noen javax.mail.AuthenticationFailedException kastet av JavaMailSender vil bli håndtert av kontrolleren.

3.3. Behandler bekreftelsestokenparameteren

Når brukeren mottarBekreft registrering”Link de burde klikke på den.

Når de gjør det, vil kontrolleren trekke ut verdien av tokenparameteren i den resulterende GET-forespørselen, og vil bruke den til å aktivere Bruker.

La oss se denne prosessen i eksempel 3.3.1 .:

Eksempel 3.3.1. - RegistrationController Behandler registreringsbekreftelsen

@Autowired privat IUserService-tjeneste; @GetMapping ("/ regitrationConfirm") offentlig strengbekreftelsesregistrering (WebRequest-forespørsel, modellmodell, @RequestParam ("token") String-token) {Locale locale = request.getLocale (); VerificationToken verificationToken = service.getVerificationToken (token); if (verificationToken == null) {Strengmelding = messages.getMessage ("auth.message.invalidToken", null, locale); model.addAttribute ("melding", melding); return "redirect: /badUser.html? lang =" + locale.getLanguage (); } Brukerbruker = verificationToken.getUser (); Kalender cal = Calendar.getInstance (); if ((verificationToken.getExpiryDate (). getTime () - cal.getTime (). getTime ()) <= 0) {String messageValue = messages.getMessage ("auth.message.expired", null, locale) model.addAttribute ("melding", messageValue); return "redirect: /badUser.html? lang =" + locale.getLanguage (); } user.setEnabled (true); service.saveRegisteredUser (bruker); returner "redirect: /login.html? lang =" + request.getLocale (). getLanguage (); }

Brukeren blir omdirigert til en feilside med tilhørende melding hvis:

  1. De VerificationToken eksisterer ikke, av en eller annen grunn eller
  2. De VerificationToken har utgått

Se eksempel 3.3.2. for å se feilsiden.

Eksempel 3.3.2. - Den badUser.html

Som vi kan se, nå MyUserDetailsService bruker ikke aktivert brukerens flagg - og slik vil det bare tillate at brukeren kan autentisere.

Nå skal vi legge til en AuthenticationFailureHandler for å tilpasse unntaksmeldingene som kommer fra MyUserDetailsService. Våre CustomAuthenticationFailureHandler er vist i eksempel 4.2.:

Eksempel 4.2. - CustomAuthenticationFailureHandler:

@Komponent offentlig klasse CustomAuthenticationFailureHandler utvider SimpleUrlAuthenticationFailureHandler {@Autowired private MessageSource-meldinger; @Autowired private LocaleResolver localeResolver; @Override public void onAuthenticationFailure (HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) kaster IOException, ServletException {setDefaultFailureUrl ("/ login.html? Error = true"); super.onAuthenticationFailure (forespørsel, svar, unntak); Locale locale = localeResolver.resolveLocale (forespørsel); Streng errorMessage = messages.getMessage ("melding.badCredentials", null, lokal) hvis (exception.getMessage (). equalsIgnoreCase ("Brukeren er deaktivert")) {errorMessage = messages.getMessage ("auth.message.disabled", null, locale); } annet hvis (exception.getMessage (). equalsIgnoreCase ("Brukerkontoen er utløpt")) {errorMessage = messages.getMessage ("auth.message.expired", null, locale); } request.getSession (). setAttribute (WebAttributes.AUTHENTICATION_EXCEPTION, errorMessage); }}

Vi må endre login.html for å vise feilmeldingene.

Eksempel 4.3. - Vis feilmeldinger kl login.html:

 feil 

5. Tilpasse utholdenhetslaget

La oss nå gi den faktiske implementeringen av noen av disse operasjonene som involverer bekreftelsestokenet, så vel som brukerne.

Vi dekker:

  1. En ny VerificationTokenRepository
  2. Nye metoder i IUserInterface og implementeringen av nye CRUD-operasjoner som trengs

Eksempler 5.1 - 5.3. vise de nye grensesnittene og implementeringen:

Eksempel 5.1. - Den VerificationTokenRepository

offentlig grensesnitt VerificationTokenRepository utvider JpaRepository {VerificationToken findByToken (strengtegn); VerificationToken findByUser (brukerbruker); }

Eksempel 5.2. - Den IUserService Grensesnitt

offentlig grensesnitt IUserService {User registerNewUserAccount (UserDto userDto) kaster UserAlreadyExistException; User getUser (String verificationToken); ugyldig saveRegisteredUser (brukerbruker); ugyldig createVerificationToken (brukerbruker, strengtegn); VerificationToken getVerificationToken (String VerificationToken); }

Eksempel 5.3. De UserService

@Service @Transactional public class UserService implementerer IUserService {@Autowired private UserRepository repository; @Autowired private VerificationTokenRepository tokenRepository; @ Override public User registerNewUserAccount (UserDto userDto) kaster UserAlreadyExistException {if (emailExist (userDto.getEmail ())) {throw new UserAlreadyExistException ("Det er en konto med den e-postadressen:" + userDto.getEmail ()); } Brukerbruker = ny bruker (); user.setFirstName (userDto.getFirstName ()); user.setLastName (userDto.getLastName ()); user.setPassword (userDto.getPassword ()); user.setEmail (userDto.getEmail ()); user.setRole (ny rolle (Integer.valueOf (1), bruker)); returner repository.save (bruker); } privat boolsk emailExist (streng e-post) {return userRepository.findByEmail (email)! = null; } @ Override public User getUser (String verificationToken) {User user = tokenRepository.findByToken (verificationToken) .getUser (); retur bruker; } @Override public VerificationToken getVerificationToken (String VerificationToken) {return tokenRepository.findByToken (VerificationToken); } @ Overstyr offentlig tomrom saveRegisteredUser (brukerbruker) {repository.save (bruker); } @ Override public void createVerificationToken (brukerbruker, strengtegn) {VerificationToken myToken = ny VerificationToken (token, bruker); tokenRepository.save (myToken); }}

6. Konklusjon

I denne artikkelen har vi utvidet registreringsprosessen til å omfatte en e-postbasert aktivering av konto.

Kontoaktiveringlogikken krever at du sender et bekreftelsestoken til brukeren via e-post slik at de kan sende den tilbake til kontrolleren for å bekrefte identiteten.

Implementeringen av denne Registration with Spring Security-opplæringen finner du i GitHub-prosjektet - dette er et Eclipse-basert prosjekt, så det skal være enkelt å importere og kjøre som det er.

Neste » Vårsikkerhetsregistrering - Send bekreftelses-e-post på nytt « Forrige Registreringsprosessen med vårsikkerhet

$config[zx-auto] not found$config[zx-overlay] not found