Proljetna sigurnost - resetirajte lozinku

Ovaj je članak dio serije: • Proljetni vodič za sigurnosnu registraciju

• Postupak registracije s proljetnom sigurnošću

• Registracija - Aktivirajte novi račun e-poštom

• Proljetna sigurnosna registracija - ponovno pošaljite e-poštu za potvrdu

• Registracija s Spring Security - kodiranje lozinkom

• API za registraciju postaje RESTful

• Proljetna sigurnost - resetiranje lozinke (trenutni članak) • registracija - jačina i pravila lozinke

• Ažuriranje lozinke

1. Pregled

U ovom uputstvu nastavljamo s kontinuiranim Registracija u Spring Security niz s pogledom Osnovni "Zaboravio sam lozinku”Značajka - tako da korisnik može sigurno resetirati vlastitu lozinku kada to zatreba.

2. Zatražite poništavanje lozinke

Tok resetiranja lozinke obično započinje kada korisnik klikne na neku tipku "reset" na stranici za prijavu. Zatim od korisnika možemo zatražiti njegovu adresu e-pošte ili druge identifikacijske podatke. Nakon potvrde možemo generirati token i poslati e-poštu korisniku.

Sljedeći dijagram vizualizira tijek koji ćemo implementirati u ovaj članak:

3. Token za poništavanje lozinke

Počnimo s izradom a PasswordResetToken entitet koji će ga koristiti za poništavanje korisničke lozinke:

@Entity javna klasa PasswordResetToken {private static final int EXPIRATION = 60 * 24; @Id @GeneratedValue (strategija = GenerationType.AUTO) private Long id; privatni niz znakova; @OneToOne (targetEntity = User.class, fetch = FetchType.EAGER) @JoinColumn (nullable = false, name = "user_id") privatni korisnik; privatni Datum istekaDat; }

Kada se pokrene resetiranje lozinke - stvorit će se token i posebna će se veza koja sadrži ovaj token poslati korisniku.

Token i veza bit će valjani samo određeno vrijeme (u ovom primjeru 24 sata).

4. zaboravioPassword.html

Prva stranica u procesu je "Zaboravio sam lozinku”Stranici - gdje se od korisnika traži njegova adresa e-pošte kako bi započeo stvarni postupak resetiranja.

Dakle - izradimo jednostavno zaboravioPassword.html traženje od korisnika adrese e-pošte:

resetirati

prijava za poništavanje e-pošte prijava var serverContext = [[@ {/}]]; funkcija resetPass () {var email = $ ("# email"). val (); $ .post (serverContext + "user / resetPassword", {email: email}, funkcija (podaci) {window.location.href = serverContext + "login? message =" + data.message;}) .fail (funkcija (podaci ) {if (data.responseJSON.error.indexOf ("MailError")> -1) {window.location.href = serverContext + "emailError.html";} else {window.location.href = serverContext + "prijava? poruka? = "+ data.responseJSON.message;}}); }

Sada se moramo povezati s ovim novim “resetiranje lozinke”Sa stranice za prijavu:

resetirati

5. Stvorite PasswordResetToken

Krenimo od stvaranja novog PasswordResetToken i pošaljite ga e-poštom korisniku:

@PostMapping ("/ user / resetPassword") public GenericResponse resetPassword (HttpServletRequest zahtjev, @RequestParam ("email") String userEmail) {User user = userService.findUserByEmail (userEmail); if (user == null) {baciti novi UserNotFoundException (); } Oznaka niza = UUID.randomUUID (). ToString (); userService.createPasswordResetTokenForUser (korisnik, token); mailSender.send (constructResetTokenEmail (getAppUrl (zahtjev), request.getLocale (), token, korisnik)); vrati novi GenericResponse (messages.getMessage ("message.resetPasswordEmail", null, request.getLocale ())); }

A ovdje je createPasswordResetTokenForUser () metoda:

javna praznina createPasswordResetTokenForUser (Korisnik korisnik, žeton žetona) {PasswordResetToken myToken = nova PasswordResetToken (token, korisnik); passwordTokenRepository.save (myToken); }

I ovdje je metoda constructResetTokenEmail () - koristi se za slanje e-pošte s tokenom za resetiranje:

private SimpleMailMessage constructResetTokenEmail (String contextPath, Locale locale, String token, User user) {String url = contextPath + "/ user / changePassword? token =" + token; Niz poruke = messages.getMessage ("message.resetPassword", null, locale); return constructEmail ("Reset Password", poruka + "\ r \ n" + url, korisnik); } private SimpleMailMessage constructEmail (Predmet niza, Tijelo niza, Korisnički korisnik) {SimpleMailMessage email = new SimpleMailMessage (); email.setSubject (subject); email.setText (tijelo); email.setTo (user.getEmail ()); email.setFrom (env.getProperty ("support.email")); vratiti e-mail; }

Primijetite kako smo koristili jednostavan objekt GenericResponse da predstavimo svoj odgovor klijentu:

javna klasa GenericResponse {privatna niz poruka; privatna pogreška niza; javni GenericResponse (String poruka) {super (); this.message = poruka; } javni GenericResponse (poruka niza, pogreška niza) {super (); this.message = poruka; this.error = pogreška; }}

6. Provjerite PasswordResetToken

Jednom kada korisnik klikne na vezu u svojoj e-pošti, user / changePassword krajnja točka:

  • provjerava je li token valjan i
  • poklanja korisniku updatePassword stranicu, gdje može unijeti novu lozinku

Nova lozinka i token potom se prenose na user / savePassword krajnja točka:

Korisnik dobiva e-poštu s jedinstvenom vezom za resetiranje lozinke i klikne na vezu:

@GetMapping ("/ user / changePassword") javni niz showChangePasswordPage (lokalizacija, model modela, @RequestParam ("token") žeton žetona) {Rezultat niza = securityService.validatePasswordResetToken (žeton); if (result! = null) {String message = messages.getMessage ("auth.message." + rezultat, null, locale); vrati "preusmjeravanje: /login.html? lang =" + locale.getLanguage () + "& message =" + poruka; } else {model.addAttribute ("token", žeton); vrati "preusmjeravanje: /updatePassword.html? lang =" + locale.getLanguage (); }}

A ovdje je validatePasswordResetToken () metoda:

javni String validatePasswordResetToken (žeton niza) {konačni PasswordResetToken passToken = passwordTokenRepository.findByToken (žeton); return! isTokenFound (passToken)? "invalidToken": isTokenExpired (passToken)? "isteklo": null; } private boolean isTokenFound (PasswordResetToken passToken) {return passToken! = null; } private boolean isTokenExpired (PasswordResetToken passToken) {final Calendar cal = Calendar.getInstance (); vrati passToken.getExpiryDate (). before (cal.getTime ()); }

7. Promijenite lozinku

U ovom trenutku korisnik vidi jednostavno Poništavanje lozinke stranica - gdje je jedina moguća opcija unesite novu lozinku:

7.1. updatePassword.html

resetirati

lozinka potvrda pogreške tokena pošalji var serverContext = [[@ {/}]]; $ (document) .ready (function () {$ ('form'). submit (function (event) {savePass (event);}); $ (": password"). keyup (function () {if ($ ("#password"). val ()! = $ ("# matchPassword"). val ()) {$ ("# globalError"). show (). html (/ * [[# {PasswordMatches.user}] ] * /);} else {$ ("# globalError"). html (""). hide ();}});}); funkcija savePass (događaj) {event.preventDefault (); if ($ ("# lozinka"). val ()! = $ ("# matchPassword"). val ()) {$ ("# globalError"). show (). html (/ * [[# {PasswordMatches. korisnik}]]*/); povratak; } var formData = $ ('obrazac'). serialize (); $ .post (serverContext + "user / savePassword", formData, funkcija (podaci) {window.location.href = serverContext + "login? message =" + data.message;}) .fail (funkcija (podaci) {if ( data.responseJSON.error.indexOf ("InternalError")> -1) {window.location.href = serverContext + "login? message =" + data.responseJSON.message;} else {var error = $ .parseJSON (data. responseJSON.message); $ .each (pogreške, funkcija (indeks, stavka) {$ ("# globalError"). show (). html (item.defaultMessage);}); pogreške = $ .parseJSON (data.responseJSON. pogreška); $ .each (pogreške, funkcija (indeks, stavka) {$ ("# globalError"). show (). append (item.defaultMessage + "

"); }); } }); }

Imajte na umu da pokazujemo token za resetiranje i prosljeđujemo ga kao POST parametar u sljedećem pozivu za spremanje lozinke.

7.2. Spremite lozinku

Konačno, kada se preda prethodni zahtjev za objavom - nova korisnička lozinka se sprema:

@PostMapping ("/ user / savePassword") public GenericResponse savePassword (konačna lokalizacija, @Valid PasswordDto passwordDto) {Rezultat niza = securityUserService.validatePasswordResetToken (passwordDto.getToken ()); if (result! = null) {return new GenericResponse (messages.getMessage ("auth.message." + rezultat, null, locale)); } Izborni user = userService.getUserByPasswordResetToken (passwordDto.getToken ()); if (user.isPresent ()) {userService.changeUserPassword (user.get (), passwordDto.getNewPassword ()); vrati novi GenericResponse (messages.getMessage ("message.resetPasswordSuc", null, locale)); } else {vratiti novi GenericResponse (messages.getMessage ("auth.message.invalid", null, locale)); }}

A ovdje je changeUserPassword () metoda:

javna promjena praznineUserPassword (Korisnički korisnik, Lozinka niza) {user.setPassword (passwordEncoder.encode (lozinka)); repository.save (korisnik); }

I PasswordDto:

javna klasa PasswordDto {private String oldPassword; privatni niz znakova; @ValidPassword privatni niz newPassword; } 

8. Zaključak

U ovom smo članku implementirali jednostavnu, ali vrlo korisnu značajku za zreli postupak provjere autentičnosti - mogućnost poništavanja vlastite lozinke kao korisnika sustava.

The puna provedba ovog vodiča možete pronaći u projektu GitHub - ovo je projekt zasnovan na Eclipseu, pa bi ga trebalo lako uvesti i pokrenuti kakav jest.

Sljedeći » Registracija - Snaga lozinke i pravila « Prethodno API za registraciju postaje RESTful

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