Registreringsprocessen med forårssikkerhed
• Registreringsprocessen med Spring Security (nuværende artikel) • 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
• Spring Security - Nulstil din adgangskode
• Registrering - adgangskodestyrke og regler
• Opdatering af din adgangskode
1. Oversigt
I denne artikel implementerer vi en grundlæggende registreringsproces med Spring Security. Dette bygger på de begreber, der blev undersøgt i den forrige artikel, hvor vi kiggede på login.
Målet her er at tilføje en fuld registreringsproces der gør det muligt for en bruger at tilmelde sig, validerer og vedvarer brugerdata.
2. Registreringssiden
Først - lad os implementere en simpel registreringsside, der vises følgende felter:
- navn (for-og efternavn)
- adgangskode (og bekræftelsesfelt for adgangskode)
Følgende eksempel viser en simpel registrering.html side:
Eksempel 2.1.
form
først Valideringsfejl
sidst Valideringsfejl
e-mail Valideringsfejl
adgangskode Valideringsfejl
bekræft indsend login
3.Brugerens DTO-objekt
Vi har brug for en Dataoverførselsobjekt at sende alle registreringsoplysningerne til vores Spring backend. Det DTO objektet skal have alle de oplysninger, vi skal bruge senere, når vi opretter og udfylder vores Bruger objekt:
offentlig klasse UserDto {@NotNull @NotEmpty privat streng fornavn; @NotNull @NotEmpty privat streng efternavn; @NotNull @NotEmpty privat strengadgangskode; private String matchingPassword; @NotNull @NotEmpty privat strengemail; // standard getters og setter}
Bemærk, at vi brugte standard javax.validation bemærkninger på felterne i DTO-objektet. Senere vil vi også implementere vores egne brugerdefinerede valideringsanmærkninger for at validere formatet på e-mail-adressen samt til bekræftelse af adgangskoden. (se Afsnit 5)
4. Registreringscontrolleren
EN Tilmelde link på Log på siden fører brugeren til registrering side. Denne back-end for denne side bor i registreringscontrolleren og er kortlagt til “/ Bruger / registrering”:
Eksempel 4.1. - Det showRegistration Metode
@GetMapping ("/ bruger / registrering") offentlig String showRegistrationForm (WebRequest-anmodning, modelmodel) {UserDto userDto = ny UserDto (); model.addAttribute ("bruger", userDto); returner "registrering" }
Når controlleren modtager anmodningen “/ Bruger / registrering”, det skaber det nye UserDto objekt, der vil bakke op registrering form, binder den og vender tilbage - ret ligetil.
5. Validering af registreringsdata
Dernæst - lad os se på de valideringer, som controlleren udfører, når han registrerer en ny konto:
- Alle påkrævede felter er udfyldt (Ingen tomme eller null felter)
- E-mail-adressen er gyldig (velformet)
- Feltet til bekræftelse af adgangskode matcher feltet for adgangskode
- Kontoen findes ikke allerede
5.1. Den indbyggede validering
Til de enkle kontroller bruger vi ud af boksen bønnevalideringsanmærkninger på DTO-objektet - bemærkninger som @NotNull, @NotEmpty, etc.
For at udløse valideringsprocessen annoterer vi blot objektet i controller-laget med @Gyldig kommentar:
offentligt ModelAndView registerUserAccount (@ModelAttribute ("bruger") @Valid UserDto userDto, HttpServletRequest anmodning, fejl fejl) {...}
5.2. Brugerdefineret validering for at kontrollere e-mail-gyldighed
Næste - lad os validere e-mail-adressen og sikre, at den er velformet. Vi skal bygge en brugerdefineret validator for det såvel som en brugerdefineret validering annotation - lad os kalde det @ValidEmail.
En hurtig sidenote her - vi ruller vores egen brugerdefinerede kommentar i stedet for dvale@E-mail fordi dvale overvejer det gamle intranetadresseformat: [e-mail beskyttet] som gyldig (se Stackoverflow-artiklen), hvilket ikke er godt.
Her er e-mail-valideringsannotationen og den brugerdefinerede validator:
Eksempel 5.2.1. - Den brugerdefinerede kommentar til validering af e-mail
@Target ({TYPE, FIELD, ANNOTATION_TYPE}) @Retention (RUNTIME) @Constraint (validatedBy = EmailValidator.class) @Documented public @interface ValidEmail {Strengmeddelelse () standard "Ugyldig e-mail"; Klasse [] grupper () standard {}; Klasse [] nyttelast () standard {}; }
Bemærk, at vi har defineret kommentaren på MARK niveau - da det er her, det gælder konceptuelt.
Eksempel 5.2.2. - Brugeren E-mailValidator:
offentlig klasse EmailValidator implementerer ConstraintValidator {privat mønster mønster; privat Matcher matcher; privat statisk endelig streng 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-mail) {mønster = Mønster.kompil (EMAIL_PATTERN); matcher = mønster. matcher (e-mail); returner matcher.matches (); }}
Lad os nu brug den nye kommentar på vores UserDto implementering:
@ValidEmail @NotNull @NotEmpty privat streng-mail;
5.3. Brug af brugerdefineret validering til bekræftelse af adgangskode
Vi har også brug for en brugerdefineret kommentar og validator for at sikre, at adgangskode og matchingPassword felter matcher:
Eksempel 5.3.1. - Den brugerdefinerede kommentar til validering af adgangskodebekræftelse
@Target ({TYPE, ANNOTATION_TYPE}) @Retention (RUNTIME) @Constraint (validatedBy = PasswordMatchesValidator.class) @Documented public @interface PasswordMatches {Strengmeddelelse () standard "Adgangskoder stemmer ikke overens"; Klasse [] grupper () standard {}; Klasse [] nyttelast () standard {}; }
Bemærk, at @Mål kommentar indikerer, at dette er en TYPE annotering på niveau. Dette er fordi vi har brug for det hele UserDto modsætter sig at udføre valideringen.
Den brugerdefinerede validator, der kaldes til ved denne kommentar, vises nedenfor:
Eksempel 5.3.2. Det PasswordMatchesValidator Custom 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 (). er lig med (user.getMatchingPassword ()); }}
Nu, den @PasswordMatches annotering skal anvendes på vores UserDto objekt:
@PasswordMatches offentlig klasse UserDto {...}
Alle brugerdefinerede valideringer evalueres naturligvis sammen med alle standardkommentarer, når hele valideringsprocessen kører.
5.4. Kontroller, at kontoen ikke allerede findes
Den fjerde kontrol, vi implementerer, er at bekræfte, at e-mail konto findes ikke allerede i databasen.
Dette udføres, når formularen er valideret, og det gøres ved hjælp af UserService implementering.
Eksempel 5.4.1. - Controlleren createUserAccount Metode Opkald til UserService Object
@PostMapping ("/ bruger / registrering") offentlig ModelAndView registerUserAccount (@ModelAttribute ("bruger") @Valid UserDto userDto, HttpServletRequest anmodning, Fejlfejl) {prøv {Brugerregistreret = userService.registerNewUserAccount (userDto); } fange (UserAlreadyExistException uaeEx) {mav.addObject ("meddelelse", "Der findes allerede en konto for det brugernavn / e-mail."); returnere mav; } // resten af implementeringen}
Eksempel 5.4.2. - BrugerService Kontroller for duplikerede e-mails
@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 ("Der er en konto med den e-mail-adresse:" + userDto.getEmail ()); } ... // resten af registreringshandlingen} privat boolsk emailExist (streng-e-mail) {return userRepository.findByEmail (email)! = null; }}
UserService er afhængig af UserRepository klasse for at kontrollere, om en bruger med en given e-mail-adresse allerede findes i databasen.
Nu - den faktiske implementering af UserRepository i persistenslaget er ikke relevant for den aktuelle artikel. En hurtig måde er selvfølgelig at bruge Spring Data til at generere lageret. Endelig - lad os implementere registreringslogikken i vores controller-lag: Eksempel 6.1.1. - Det RegisterAccount Metode i controlleren Ting at bemærke i ovenstående kode: Lad os afslutte implementeringen af registreringsoperationen i UserService: Eksempel 7.1. Det IUserService Interface Eksempel 7.2. - Det UserService Klasse I vores tidligere artikel brugte login hårdt kodede legitimationsoplysninger. Lad os ændre det og Brug de nyregistrerede brugeroplysninger og legitimationsoplysninger. Vi implementerer en brugerdefineret UserDetailsService for at kontrollere legitimationsoplysningerne for login fra persistenslaget. Lad os starte med den tilpassede brugerinformation service implementering: For at aktivere den nye brugertjeneste i Spring Security-konfigurationen - skal vi blot tilføje en reference til UserDetailsService inde i godkendelses-manager element og tilføj UserDetailsService bønne: Eksempel 8.2. - Godkendelsesadministratoren og UserDetailsService Eller via Java-konfiguration: Og vi er færdige - en komplet og næsten produktionsklar registreringsproces implementeret med Spring Security og Spring MVC. Dernæst skal vi diskutere processen med at aktivere den nyregistrerede konto ved at bekræfte e-mail fra den nye bruger. Implementeringen af dette Spring Security REST-tutorial 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.6. Vedvarende data og efterbehandling af formularbehandling
@PostMapping ("/ bruger / registrering") offentlig ModelAndView registerUserAccount (@ModelAttribute ("bruger") @Valid UserDto userDto, HttpServletRequest anmodning, Fejlfejl) {prøv {Brugerregistreret = userService.registerNewUserAccount (userDto); } fange (UserAlreadyExistException uaeEx) {mav.addObject ("meddelelse", "Der findes allerede en konto for dette brugernavn / e-mail."); returnere mav; } returner ny ModelAndView ("successRegister", "user", userDto); }
7.Det UserService - Registrer operation
offentlig grænseflade IUserService {User registerNewUserAccount (UserDto userDto) kaster UserAlreadyExistException; }
@Service offentlig klasse UserService implementerer IUserService {@Autowired private UserRepository repository; @Transactional @ Override public User registerNewUserAccount (UserDto userDto) throw UserAlreadyExistException {if (emailExists (userDto.getEmail ())) {throw new UserAlreadyExistException ("Der er en konto med den e-mail-adresse: + userDto.getEmail ());} Bruger bruger = ny bruger (); user.setFirstName (userDto.getFirstName ()); user.setLastName (userDto.getLastName ()); user.setPassword (userDto.getPassword ()); user.setEmail (userDto.getEmail ()) ; user.setRoles (Arrays.asList ("ROLE_USER")); returner repository.save (bruger);} private boolske emailExists (streng e-mail) {return userRepository.findByEmail (email)! = null;}}
8. Indlæser brugeroplysninger til sikkerhedslogin
8.1. Den brugerdefinerede UserDetailsService
@Service @Transactional public class MyUserDetailsService implementerer UserDetailsService {@Autowired privat UserRepository userRepository; // offentlige UserDetails loadUserByUsername (String email) kaster UsernameNotFoundException {User user = userRepository.findByEmail (email); if (user == null) {throw new UsernameNotFoundException ("Ingen bruger fundet med brugernavn:" + email); } boolsk aktiveret = sandt; boolsk accountNonExpired = sand; boolske legitimationsoplysningerNonExpired = true; boolsk accountNonLocked = sand; returner nyt org.springframework.security.core.userdetails.User (user.getEmail (), user.getPassword (). toLowerCase (), aktiveret, accountNonExpired, credentialsNonExpired, accountNonLocked, getAuthorities (user.getRoles ())); } privat statisk liste getAuthorities (listeroller) {Liste autoriteter = ny ArrayList (); for (String rolle: roller) {autoriteter.add (ny SimpleGrantedAuthority (rolle)); } returneringsmyndigheder }}
8.2. Aktivér den nye godkendelsesudbyder
@Autowired privat MyUserDetailsService userDetailsService; @ Override beskyttet ugyldig konfiguration (AuthenticationManagerBuilder auth) kaster Undtagelse {auth.userDetailsService (userDetailsService); }
9. Konklusion