Spring Security - Nulstil din adgangskode

Denne artikel er en del af en serie: • Vejledning i Spring Security Registration

• Registreringsprocessen med forårssikkerhed

• Registrering - Aktiver en ny konto via e-mail

• Forårsikkerhedsregistrering - Send bekræftelses-e-mail igen

• Registrering med Spring Security - kodning af adgangskode

• Registrerings-API'en bliver RESTful

• Forårsikkerhed - Nulstil din adgangskode (nuværende artikel) • Registrering - Adgangskodestyrke og regler

• Opdatering af din adgangskode

1. Oversigt

I denne vejledning - fortsætter vi det igangværende Registrering hos Spring Security serie med et kig på det basale "jeg har glemt mit kodeord”-Funktion - så brugeren sikkert kan nulstille deres eget kodeord, når de har brug for det.

2. Anmod om nulstilling af din adgangskode

En nulstilling af adgangskodestrøm starter typisk, når brugeren klikker på en slags “nulstil” -knap på login-siden. Derefter kan vi bede brugeren om deres e-mail-adresse eller andre identificerende oplysninger. Når det er bekræftet, kan vi generere et token og sende en e-mail til brugeren.

Følgende diagram visualiserer det flow, som vi implementerer i denne artikel:

3. Token til nulstilling af adgangskode

Lad os starte med at oprette en PasswordResetToken enhed til at bruge den til nulstilling af brugerens adgangskode:

@Entity offentlig klasse PasswordResetToken {privat statisk endelig int EXPIRATION = 60 * 24; @Id @GeneratedValue (strategi = GenerationType.AUTO) privat Lang id; privat String token; @OneToOne (targetEntity = User.class, fetch = FetchType.EAGER) @JoinColumn (nullable = false, name = "user_id") privat brugerbruger; privat Dato udløbsdato; }

Når en nulstilling af adgangskode udløses - oprettes et token og et specielt link indeholdende dette token vil blive sendt til brugeren.

Tokenet og linket er kun gyldigt i en bestemt periode (24 timer i dette eksempel).

4. glemtePassword.html

Den første side i processen er det "jeg har glemt mit kodeord" side - hvor brugeren bliver bedt om at angive deres e-mail-adresse for at den faktiske nulstillingsproces kan starte.

Så - lad os lave et simpelt glemtePassword.html beder brugeren om en e-mail-adresse:

Nulstil

registrering af e-mail-login login var serverContext = [[@ {/}]]; funktion resetPass () {var email = $ ("# email"). val (); $ .post (serverContext + "bruger / resetPassword", {e-mail: e-mail}, funktion (data) {window.location.href = serverContext + "login? besked =" + data.message;}). mislykket (funktion (data ) {hvis (data.responseJSON.error.indexOf ("MailError")> -1) {window.location.href = serverContext + "emailError.html";} ellers {window.location.href = serverContext + "login-meddelelse = "+ data.responseJSON.message;}}); }

Vi er nu nødt til at linke til dette nye “nulstille kodeord”Side fra login siden:

Nulstil

5. Opret PasswordResetToken

Lad os starte med at oprette det nye PasswordResetToken og send det via e-mail til brugeren:

@PostMapping ("/ user / resetPassword") offentlig GenericResponse resetPassword (HttpServletRequest anmodning, @RequestParam ("email") String userEmail) {Bruger bruger = userService.findUserByEmail (userEmail); hvis (bruger == null) {kast ny UserNotFoundException (); } String token = UUID.randomUUID (). ToString (); userService.createPasswordResetTokenForUser (bruger, token); mailSender.send (constructResetTokenEmail (getAppUrl (anmodning), request.getLocale (), token, bruger)); returner nyt GenericResponse (messages.getMessage ("message.resetPasswordEmail", null, request.getLocale ())); }

Og her er createPasswordResetTokenForUser () metode:

public void createPasswordResetTokenForUser (Brugerbruger, String token) {PasswordResetToken myToken = nyt PasswordResetToken (token, bruger); passwordTokenRepository.save (myToken); }

Og her er metoden constructResetTokenEmail () - bruges til at sende en e-mail med reset-token:

privat SimpleMailMessage constructResetTokenEmail (String contextPath, Locale locale, String token, User user) {String url = contextPath + "/ user / changePassword? token =" + token; Strengmeddelelse = messages.getMessage ("message.resetPassword", null, locale); returner constructEmail ("Nulstil adgangskode", besked + "\ r \ n" + url, bruger); } privat SimpleMailMessage constructEmail (strengemne, strengtekst, brugerbruger) {SimpleMailMessage-e-mail = ny SimpleMailMessage (); email.setSubject (emne); email.setText (body); email.setTo (user.getEmail ()); email.setFrom (env.getProperty ("support.email")); returnere e-mail; }

Bemærk hvordan vi brugte et simpelt objekt GenericResponse til at repræsentere vores svar over for klienten:

offentlig klasse GenericResponse {privat streng besked; privat strengfejl; offentlig GenericResponse (streng besked) {super (); denne besked = besked; } offentlig GenericResponse (strengmeddelelse, strengfejl) {super (); denne besked = besked; this.error = fejl; }}

6. Kontroller PasswordResetToken

Når brugeren klikker på linket i deres e-mail, vises bruger / changePassword slutpunkt:

  • verificerer, at tokenet er gyldigt og
  • præsenterer brugeren for updatePassword side, hvor han kan indtaste en ny adgangskode

Den nye adgangskode og token sendes derefter til bruger / gemPassword slutpunkt:

Brugeren får e-mailen med det unikke link til nulstilling af deres adgangskode og klikker på linket:

@GetMapping ("/ user / changePassword") offentlig streng showChangePasswordPage (landestandard, modelmodel, @RequestParam ("token") String token) {String result = securityService.validatePasswordResetToken (token); hvis (resultat! = null) {Strengmeddelelse = messages.getMessage ("auth.message." + resultat, null, landestandard); returner "redirect: /login.html? lang =" + locale.getLanguage () + "& message =" + meddelelse; } andet {model.addAttribute ("token", token); returner "redirect: /updatePassword.html? lang =" + locale.getLanguage (); }}

Og her er validatePasswordResetToken () metode:

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

7. Skift adgangskoden

På dette tidspunkt ser brugeren det enkle Nulstil kodeord side - hvor den eneste mulige mulighed er at give en ny adgangskode:

7.1. updatePassword.html

Nulstil

adgangskodebekræft tokenfejl indsend var serverContext = [[@ {/}]]; $ (dokument). klar (funktion () {$ ('form'). indsend (funktion (begivenhed) {savePass (begivenhed);}); $ (": adgangskode"). keyup (funktion () {hvis ($ ("#password"). val ()! = $ ("# matchPassword"). val ()) {$ ("# globalError"). vis (). html (/ * [[# {PasswordMatches.user}] ] * /);} andet {$ ("# globalError"). html (""). skjul ();}});}); funktion savePass (event) {event.preventDefault (); if ($ ("# password"). val ()! = $ ("# matchPassword"). val ()) {$ ("# globalError"). show (). html (/ * [[# {PasswordMatches. bruger}]]*/); Vend tilbage; } var formData = $ ('form'). serialize (); $ .post (serverContext + "bruger / savePassword", formData, funktion (data) {window.location.href = serverContext + "login? besked =" + data.message;}). mislykket (funktion (data) {hvis ( data.responseJSON.error.indexOf ("InternalError")> -1) {window.location.href = serverContext + "login? message =" + data.responseJSON.message;} ellers {var fejl = $ .parseJSON (data. responsJSON.message); $ .each (fejl, funktion (indeks, vare) {$ ("# globalError"). viser (). html (item.defaultMessage);}); fejl = $ .parseJSON (data.responseJSON. fejl); $ .each (fejl, funktion (indeks, vare) {$ ("# globalError"). vis (). tilføj (item.defaultMessage + "

"); }); } }); }

Bemærk, at vi viser reset-token og sender det som en POST-parameter i det følgende opkald for at gemme adgangskoden.

7.2. Gem adgangskoden

Endelig, når den forrige postanmodning indsendes - den nye brugeradgangskode gemmes:

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

Og her er changeUserPassword () metode:

offentlig ugyldig ændringUserPassword (brugerbruger, strengadgangskode) {user.setPassword (passwordEncoder.encode (adgangskode)); repository.save (bruger); }

Og PasswordDto:

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

8. Konklusion

I denne artikel implementerede vi en enkel, men meget nyttig funktion til en moden godkendelsesproces - muligheden for at nulstille din egen adgangskode som bruger af systemet.

Det fuld implementering af denne vejledning kan findes i GitHub-projektet - dette er et Eclipse-baseret projekt, så det skal være let at importere og køre som det er.

Næste » Registrering - adgangskodestyrke og regler « Tidligere Registrerings-API'en bliver RESTful