Spring Security - Tilbakestill passordet ditt

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

• Vårsikkerhetsregistrering - Send bekreftelses-e-post på nytt

• Registrering med vårsikkerhet - passordkoding

• Registrerings-API-et blir RESTful

• Vårsikkerhet - Tilbakestill passordet ditt (nåværende artikkel) • Registrering - Passordstyrke og regler

• Oppdatere passordet ditt

1. Oversikt

I denne veiledningen - vi fortsetter den pågående Registrering hos Spring Security serie med en titt på det grunnleggende "jeg glemte passordet mitt" trekk - slik at brukeren trygt kan tilbakestille sitt eget passord når de trenger det.

2. Be om tilbakestilling av passordet ditt

En tilbakestilling av passord starter vanligvis når brukeren klikker på en slags "reset" -knapp på påloggingssiden. Deretter kan vi be brukeren om deres e-postadresse eller annen identifiserende informasjon. Når det er bekreftet, kan vi generere et token og sende en e-post til brukeren.

Følgende diagram visualiserer flyten som vi implementerer i denne artikkelen:

3. Token for tilbakestilling av passord

La oss starte med å lage en PasswordResetToken enhet til å bruke den til å tilbakestille brukerens passord:

@Entity offentlig klasse PasswordResetToken {privat statisk slutt 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; }

Når tilbakestilling av passord utløses - opprettes et token og en spesiell lenke som inneholder dette tokenet vil bli sendt til brukeren.

Token og lenken vil bare være gyldig i en angitt tidsperiode (24 timer i dette eksemplet).

4. glemt Passord.html

Den første siden i prosessen er den “jeg glemte passordet mitt”-Siden - der brukeren blir bedt om sin e-postadresse for at den faktiske tilbakestillingsprosessen skal starte.

Så - la oss lage et enkelt glemt Passord.html spør brukeren om en e-postadresse:

nullstille

registrering for e-post tilbakestilling pålogging var serverContext = [[@ {/}]]; funksjon resetPass () {var email = $ ("# email"). val (); $ .post (serverContext + "user / resetPassword", {email: email}, function (data) {window.location.href = serverContext + "login? message =" + data.message;}) .fail (function (data ) {if (data.responseJSON.error.indexOf ("MailError")> -1) {window.location.href = serverContext + "emailError.html";} annet {window.location.href = serverContext + "påloggingsmelding? = "+ data.responseJSON.message;}}); }

Vi må nå lenke til dette nye “tilbakestille passord”-Siden fra påloggingssiden:

nullstille

5. Opprett PasswordResetToken

La oss starte med å lage det nye PasswordResetToken og send den via e-post til brukeren:

@PostMapping ("/ user / resetPassword") public GenericResponse resetPassword (HttpServletRequest request, @RequestParam ("email") String userEmail) {User user = userService.findUserByEmail (userEmail); hvis (bruker == null) {kast ny UserNotFoundException (); } String token = UUID.randomUUID (). ToString (); userService.createPasswordResetTokenForUser (bruker, token); mailSender.send (constructResetTokenEmail (getAppUrl (forespørsel), forespørsel.getLocale (), token, bruker)); returner nye GenericResponse (messages.getMessage ("message.resetPasswordEmail", null, request.getLocale ())); }

Og her er createPasswordResetTokenForUser () metode:

offentlig ugyldig createPasswordResetTokenForUser (brukerbruker, strengtegn) {PasswordResetToken myToken = nytt PasswordResetToken (token, bruker); passwordTokenRepository.save (myToken); }

Og her er metoden constructResetTokenEmail () - brukes til å sende en e-post med reset-token:

privat SimpleMailMessage constructResetTokenEmail (String contextPath, Locale locale, String token, User user) {String url = contextPath + "/ user / changePassword? token =" + token; Strengmelding = meldinger.getMessage ("melding.resetPassword", null, lokal) return constructEmail ("Tilbakestill passord", melding + "\ r \ n" + url, bruker); } privat SimpleMailMessage constructEmail (strengemne, strengtekst, brukerbruker) {SimpleMailMessage e-post = ny SimpleMailMessage (); email.setSubject (emne); email.setText (body); email.setTo (user.getEmail ()); email.setFrom (env.getProperty ("support.email")); returner e-post; }

Legg merke til hvordan vi brukte et enkelt objekt GenericResponse for å representere vårt svar til klienten:

offentlig klasse GenericResponse {privat strengmelding; privat strengfeil; offentlig GenericResponse (strengmelding) {super (); denne meldingen = melding; } offentlig GenericResponse (strengmelding, strengfeil) {super (); denne meldingen = melding; this.error = feil; }}

6. Kontroller PasswordResetToken

Når brukeren klikker på lenken i e-posten sin, blir bruker / endre passord sluttpunkt:

  • verifiserer at token er gyldig og
  • presenterer brukeren for updatePassword side, der han kan skrive inn et nytt passord

Det nye passordet og tokenet sendes deretter til bruker / lagre passord sluttpunkt:

Brukeren får e-posten med den unike lenken for å tilbakestille passordet, og klikker på lenken:

@GetMapping ("/ user / changePassword") offentlig String showChangePasswordPage (lokal språk, modellmodell, @RequestParam ("token") String token) {Stringresultat = securityService.validatePasswordResetToken (token); hvis (resultat! = null) {Strengmelding = meldinger.getMessage ("auth.message." + resultat, null, sted); return "redirect: /login.html? lang =" + locale.getLanguage () + "& melding =" + melding; } annet {model.addAttribute ("token", token); return "redirect: /updatePassword.html? lang =" + locale.getLanguage (); }}

Og her er validatePasswordResetToken () metode:

public String validatePasswordResetToken (String token) {final PasswordResetToken passToken = passwordTokenRepository.findByToken (token); return! isTokenFound (passToken)? "invalidToken": erTokenExpired (passToken)? "utløpt": null; } privat boolsk isTokenFound (PasswordResetToken passToken) {return passToken! = null; } privat boolsk isTokenExpired (PasswordResetToken passToken) {final Calendar cal = Calendar.getInstance (); returner passToken.getExpiryDate (). før (cal.getTime ()); }

7. Endre passordet

På dette punktet ser brukeren det enkle Reset passord side - der det eneste mulige alternativet er å oppgi et nytt passord:

7.1. updatePassword.html

nullstille

passord bekreft token feil send var serverContext = [[@ {/}]]; $ (dokument) .ready (funksjon () {$ ('skjema'). sende inn (funksjon (hendelse) {savePass (hendelse);}); $ (": passord"). keyup (funksjon () {hvis ($ ("#passord"). val ()! = $ ("# matchPassword"). val ()) {$ ("# globalError"). vis (). html (/ * [[# {PasswordMatches.user}] ] * /);} annet {$ ("# globalError"). html (""). skjul ();}});}); funksjon savePass (hendelse) {event.preventDefault (); if ($ ("# password"). val ()! = $ ("# matchPassword"). val ()) {$ ("# globalError"). show (). html (/ * [[# {PasswordMatches. bruker}]]*/); komme tilbake; } var formData = $ ('form'). serialize (); $ .post (serverContext + "user / savePassword", formData, function (data) {window.location.href = serverContext + "login? message =" + data.message;}). mislykkedes (funksjon (data) {if ( data.responseJSON.error.indexOf ("InternalError")> -1) {window.location.href = serverContext + "login? message =" + data.responseJSON.message;} annet {var feil = $ .parseJSON (data. responsJSON.message); $ .each (feil, funksjon (indeks, vare) {$ ("# globalError"). vis (). html (item.defaultMessage);}); feil = $ .parseJSON (data.responseJSON. feil); $ .each (feil, funksjon (indeks, vare) {$ ("# globalError"). vis (). legg til (item.defaultMessage + "

"); }); } }); }

Merk at vi viser reset-token og sender det som en POST-parameter i følgende samtale for å lagre passordet.

7.2. Lagre passordet

Til slutt, når den forrige innleggsforespørselen sendes - lagres det nye brukerpassordet:

@PostMapping ("/ user / savePassword") public GenericResponse savePassword (final locale locale, @Valid PasswordDto passwordDto) {String result = securityUserService.validatePasswordResetToken (passwordDto.getToken ()); if (result! = null) {return new GenericResponse (messages.getMessage ("auth.message." + result, null, locale)); } Valgfri bruker = userService.getUserByPasswordResetToken (passwordDto.getToken ()); hvis (user.isPresent ()) {userService.changeUserPassword (user.get (), passwordDto.getNewPassword ()); returner nye GenericResponse (messages.getMessage ("message.resetPasswordSuc", null, locale)); } ellers {return new GenericResponse (messages.getMessage ("auth.message.invalid", null, locale)); }}

Og her er endre brukerpassord () metode:

public void changeUserPassword (brukerbruker, strengpassord) {user.setPassword (passwordEncoder.encode (passord)); repository.save (bruker); }

Og PasswordDto:

offentlig klasse PasswordDto {private String oldPassword; private String token; @ValidPassword private String newPassword; } 

8. Konklusjon

I denne artikkelen implementerte vi en enkel, men veldig nyttig funksjon for en moden autentiseringsprosess - muligheten til å tilbakestille ditt eget passord, som bruker av systemet.

De full gjennomføring av denne opplæringen finnes i GitHub-prosjektet - dette er et formørkelsesbasert prosjekt, så det skal være enkelt å importere og kjøre som det er.

Neste » Registrering - Passordstyrke og regler « Forrige Registrerings-API-et blir RESTful

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