Registreringsprosessen med vårsikkerhet
• Registreringsprosessen med vårsikkerhet (nåværende artikkel) • 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
• Spring Security - Tilbakestill passordet ditt
• Registrering - Passordstyrke og regler
• Oppdatere passordet ditt
1. Oversikt
I denne artikkelen implementerer vi en grunnleggende registreringsprosess med Spring Security. Dette bygger på konsepter som ble utforsket i forrige artikkel, hvor vi så på innlogging.
Målet her er å legge til en full registreringsprosess som gjør det mulig for en bruker å registrere seg, validere og vedvare brukerdata.
2. Registreringssiden
Først - la oss implementere en enkel registreringsside som vises følgende felt:
- Navn (fornavn og etternavn)
- e-post
- passord (og passordbekreftelsesfelt)
Følgende eksempel viser en enkel registrering.html side:
Eksempel 2.1.
skjema
først Valideringsfeil
siste Valideringsfeil
e-post Valideringsfeil
passord Valideringsfeil
bekreft send innlogging
3.Brukerens DTO-objekt
Vi trenger en Dataoverføringsobjekt for å sende all registreringsinformasjonen til vår-backend. De DTO objektet skal ha all informasjon vi trenger senere når vi oppretter og fyller ut vår Bruker gjenstand:
offentlig klasse UserDto {@NotNull @NotEmpty privat streng fornavn; @NotNull @NotEmpty privat strengnavn; @NotNull @NotEmpty privat strengpassord; private String matchingPassword; @NotNull @NotEmpty privat streng-e-post; // standard getters og setters}
Legg merke til at vi brukte standard javax.validation merknader på feltene til DTO-objektet. Senere skal vi også implementere våre egne tilpassede valideringskommentarer for å validere formatet til e-postadressen samt for passordbekreftelsen. (se Avsnitt 5)
4. Registreringskontrolløren
EN Melde deg på lenke på Logg Inn siden tar brukeren til registrering side. Denne bakenden for den siden bor i registreringskontrolleren og er kartlagt til "/bruker registrering":
Eksempel 4.1. - Den showRegistration Metode
@GetMapping ("/ bruker / registrering") offentlig String showRegistrationForm (WebRequest-forespørsel, modellmodell) {UserDto userDto = ny UserDto (); model.addAttribute ("bruker", userDto); returner "registrering"; }
Når kontrolleren mottar forespørselen "/bruker registrering", det skaper det nye UserDto objekt som vil sikkerhetskopiere registrering form, binder den og returnerer - ganske grei.
5. Validering av registreringsdata
Neste - la oss se på valideringene som kontrolleren vil utføre når du registrerer en ny konto:
- Alle obligatoriske felt er fylt ut (Ingen tomme eller null felt)
- E-postadressen er gyldig (velformet)
- Passordbekreftelsesfeltet samsvarer med passordfeltet
- Kontoen eksisterer ikke allerede
5.1. Den innebygde valideringen
For de enkle kontrollene bruker vi utmerkelser for validering av bønne på DTO-objektet - merknader som @Ikke null, @Ikke tom, etc.
For å utløse valideringsprosessen, vil vi bare kommentere objektet i kontrollerlaget med @Gyldig kommentar:
offentlig ModelAndView registerUserAccount (@ModelAttribute ("bruker") @Valid UserDto userDto, HttpServletRequest-forespørsel, feilfeil) {...}
5.2. Tilpasset validering for å sjekke e-postgyldighet
Neste - la oss validere e-postadressen og sørge for at den er velformet. Vi skal bygge en tilpasset validator for det, så vel som en egendefinert valideringskommentar - la oss kalle det @ValidEmail.
En rask sidenote her - vi ruller vår egen tilpassede kommentar i stedet for dvalemodus@Email fordi dvalemodus vurderer det gamle formatet for intranettadresser: [e-postbeskyttet] som gyldig (se artikkelen om Stackoverflow), noe som ikke er bra.
Her er e-postvalideringsnotatet og den tilpassede validatoren:
Eksempel 5.2.1. - Den tilpassede merknaden for validering av e-post
@Target ({TYPE, FIELD, ANNOTATION_TYPE}) @Retention (RUNTIME) @Constraint (validatedBy = EmailValidator.class) @Documented public @interface ValidEmail {Strengmelding () standard "Ugyldig e-post"; Klasse [] grupper () standard {}; Klasse [] nyttelast () standard {}; }
Merk at vi har definert merknaden på FELT nivå - siden det er der det gjelder konseptuelt.
Eksempel 5.2.2. - Tollen Send e-post til Validator:
offentlig klasse EmailValidator implementerer ConstraintValidator {privat mønster mønster; privat Matcher matcher; privat statisk sluttstreng EMAIL_PATTERN = "^ [_ A-Za-z0-9 - +] + (. [_ A-Za-z0-9 -] +) * @" + "[A-Za-z0-9 -] + (. [A-Za-z0-9] +) * (. [A-Za-z] {2,}) $ "; @Override public void initialize (ValidEmail constraintAnnotation) {} @Override public boolean isValid (String email, ConstraintValidatorContext context) {return (validateEmail (email)); } privat boolsk validateEmail (streng e-post) {mønster = Pattern.compile (EMAIL_PATTERN); matcher = mønster. matcher (e-post); retur matcher.matches (); }}
La oss nå bruk den nye kommentaren på vår UserDto gjennomføring:
@ValidEmail @NotNull @NotEmpty privat streng-e-post;
5.3. Bruke egendefinert validering for passordbekreftelse
Vi trenger også en tilpasset kommentar og validator for å sikre at passord og matchingPassword felt samsvarer med:
Eksempel 5.3.1. - Den egendefinerte merknaden for validering av passordbekreftelse
@Target ({TYPE, ANNOTATION_TYPE}) @Retention (RUNTIME) @Constraint (validatedBy = PasswordMatchesValidator.class) @Documented public @interface PasswordMatches {Strengmelding () standard "Passord samsvarer ikke"; Klasse [] grupper () standard {}; Klasse [] nyttelast () standard {}; }
Legg merke til at @Mål kommentar indikerer at dette er en TYPE nivåkommentar. Dette er fordi vi trenger hele UserDto protesterer mot å utføre valideringen.
Den egendefinerte validatoren som kalles ved denne kommentaren, vises nedenfor:
Eksempel 5.3.2. De PasswordMatchesValidator Tilpasset validator
offentlig klasse PasswordMatchesValidator implementerer ConstraintValidator {@Override public void initialize (PasswordMatches constraintAnnotation) {} @Override public boolean isValid (Object obj, ConstraintValidatorContext context) {UserDto user = (UserDto) obj; returner user.getPassword (). tilsvarer (user.getMatchingPassword ()); }}
Nå, den @PasswordMatches merknader bør brukes på vår UserDto gjenstand:
@PasswordMatches offentlig klasse UserDto {...}
Alle egendefinerte valideringer blir selvfølgelig evaluert sammen med alle standardkommentarer når hele valideringsprosessen kjører.
5.4. Kontroller at kontoen ikke allerede eksisterer
Den fjerde sjekken vi implementerer er å verifisere at e-post kontoen eksisterer ikke allerede i databasen.
Dette utføres etter at skjemaet er validert, og det gjøres ved hjelp av UserService gjennomføring.
Eksempel 5.4.1. - Kontrolleren createUserAccount Metode Kaller UserService Object
@PostMapping ("/ bruker / registrering") offentlig ModelAndView registerUserAccount (@ModelAttribute ("bruker") @Valid UserDto userDto, HttpServletRequest-forespørsel, feilfeil) {prøv {User registered = userService.registerNewUserAccount (userDto); } catch (UserAlreadyExistException uaeEx) {mav.addObject ("melding", "Det finnes allerede en konto for brukernavnet / e-postadressen."); retur mav; } // resten av implementeringen}
Eksempel 5.4.2. - BrukerService Sjekker for dupliserte e-poster
@Service offentlig klasse UserService implementerer IUserService {@Autowired private UserRepository repository; @Transactional @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 ()); } ... // resten av registreringsoperasjonen} privat boolsk emailExist (streng e-post) {return userRepository.findByEmail (email)! = null; }}
UserService er avhengig av UserRepository klasse for å sjekke om en bruker med en gitt e-postadresse allerede finnes i databasen.
Nå - den faktiske implementeringen av UserRepository i utholdenhetslaget er ikke relevant for den nåværende artikkelen. En rask måte er selvfølgelig å bruke Spring Data til å generere lagringslaget. Til slutt - la oss implementere registreringslogikken i kontrollerlaget vårt: Eksempel 6.1.1. - Den Registrer Konto Metode i kontrolleren Ting å legge merke til i koden ovenfor: La oss fullføre implementeringen av registreringsoperasjonen i UserService: Eksempel 7.1. De IUserService Grensesnitt Eksempel 7.2. - Den UserService Klasse I vår forrige artikkel brukte pålogging hardkodede referanser. La oss endre det og bruke den nylig registrerte brukerinformasjonen og legitimasjon. Vi implementerer en skikk UserDetailsService for å sjekke legitimasjonen for pålogging fra utholdenhetslaget. La oss starte med den tilpassede implementeringen av tjenestene for brukerdetaljer: For å aktivere den nye brukertjenesten i Spring Security-konfigurasjonen - trenger vi bare å legge til en referanse til UserDetailsService inne i godkjenningssjef element og legg til UserDetailsService bønne: Eksempel 8.2. - Autentiseringsleder og UserDetailsService Eller via Java-konfigurasjon: Og vi er ferdige - en komplett og nesten produksjonsklar registreringsprosess implementert med Spring Security og Spring MVC. Deretter skal vi diskutere prosessen med å aktivere den nylig registrerte kontoen ved å bekrefte e-postadressen til den nye brukeren. Implementeringen av denne REST-veiledningen om vårsikkerhet finner du i GitHub-prosjektet - dette er et formørkelsesbasert prosjekt, så det skal være enkelt å importere og kjøre som det er.6. Vedvarende data og etterbehandling av skjemabehandling
@PostMapping ("/ bruker / registrering") offentlig ModelAndView registerUserAccount (@ModelAttribute ("bruker") @Valid UserDto userDto, HttpServletRequest-forespørsel, feilfeil) {prøv {User registered = userService.registerNewUserAccount (userDto); } catch (UserAlreadyExistException uaeEx) {mav.addObject ("melding", "Det finnes allerede en konto for brukernavnet / e-postadressen."); retur mav; } returner ny ModelAndView ("successRegister", "user", userDto); }
7.De UserService - Registrer operasjon
offentlig grensesnitt IUserService {User registerNewUserAccount (UserDto userDto) kaster UserAlreadyExistException; }
@Service offentlig klasse UserService implementerer IUserService {@Autowired private UserRepository repository; @Transactional @Override public User registerNewUserAccount (UserDto userDto) kaster UserAlreadyExistException {if (emailExists (userDto.getEmail ())) {throw new UserAlreadyExistException ("Det er en konto med den e-postadressen: + userDto.getEmail ());} bruker bruker = ny bruker (); bruker.setFirstName (userDto.getFirstName ()); bruker.setLastName (userDto.getLastName ()); user.setPassword (userDto.getPassword ()); user.setEmail (userDto.getEmail ()) ; user.setRoles (Arrays.asList ("ROLE_USER")); return repository.save (user);} private boolean emailExists (String email) {return userRepository.findByEmail (email)! = null;}}
8. Laster inn brukerinformasjon for sikkerhetsinnlogging
8.1. Tollen UserDetailsService
@Service @Transactional public class MyUserDetailsService implementerer UserDetailsService {@Autowired private UserRepository userRepository; // offentlige UserDetails loadUserByUsername (streng e-post) kaster UsernameNotFoundException {User user = userRepository.findByEmail (email); if (user == null) {throw new UsernameNotFoundException ("Ingen bruker funnet med brukernavn:" + e-post); } boolsk aktivert = sann; boolsk kontoNonExpired = true; boolsk legitimasjonNonExpired = true; boolsk kontoNonLocked = true; returner ny org.springframework.security.core.userdetails.User (user.getEmail (), user.getPassword (). toLowerCase (), aktivert, accountNonExpired, credentialsNonExpired, accountNonLocked, getAuthorities (user.getRoles ())); } privat statisk liste getAuthorities (listeroller) {Liste myndigheter = ny ArrayList (); for (String rolle: roller) {autoriteter.add (ny SimpleGrantedAuthority (rolle)); } returmyndigheter; }}
8.2. Aktiver den nye godkjenningsleverandøren
@Autowired private MyUserDetailsService userDetailsService; @ Override beskyttet ugyldig konfigurasjon (AuthenticationManagerBuilder auth) kaster Unntak {auth.userDetailsService (userDetailsService); }
9. Konklusjon