Two Factor Auth med vårsikkerhet
1. Oversikt
I denne opplæringen skal vi implementere tofaktorautentiseringsfunksjonalitet med en myk token og vårsikkerhet.
Vi skal legge til den nye funksjonaliteten i en eksisterende, enkel påloggingsflyt og bruke Google Authenticator-appen til å generere tokens.
Enkelt sagt er tofaktorautentisering en bekreftelsesprosess som følger det velkjente prinsippet om "noe brukeren vet og noe brukeren har".
Og så gir brukerne et ekstra "bekreftelsestoken" under autentisering - en engangskode for bekreftelse av passord basert på tidsbasert engangspassord TOTP-algoritme.
2. Maven-konfigurasjon
Først, for å kunne bruke Google Authenticator i appen vår, må vi:
- Generer hemmelig nøkkel
- Gi hemmelig nøkkel til brukeren via QR-kode
- Bekreft token som er angitt av brukeren ved hjelp av denne hemmelige nøkkelen.
Vi vil bruke et enkelt serverbibliotek for å generere / verifisere engangspassord ved å legge til følgende avhengighet til vårt pom.xml:
org.jboss.aerogear aerogear-otp-java 1.0.0
3. Brukerenhet
Deretter vil vi endre brukerenheten vår for å ha ekstra informasjon - som følger:
@Entity public class User {... private boolean isUsing2FA; privat streng hemmelighet; offentlig bruker () {super (); this.secret = Base32.random (); ...}}
Noter det:
- Vi lagrer en tilfeldig hemmelig kode for hver bruker som skal brukes senere ved generering av bekreftelseskode
- Vår 2-trinns bekreftelse er valgfri
4. Ekstra innloggingsparameter
Først må vi justere sikkerhetskonfigurasjonen for å godta ekstra parameter - bekreftelsestoken. Vi kan oppnå det ved å bruke tilpasset AuthenticationDetailsSource:
Her er vår CustomWebAuthenticationDetailsSource:
@Komponent offentlig klasse CustomWebAuthenticationDetailsSource implementerer AuthenticationDetailsSource {@Override public WebAuthenticationDetails buildDetails (HttpServletRequest context) {return new CustomWebAuthenticationDetails (context); }}
og her er CustomWebAuthenticationDetails:
offentlig klasse CustomWebAuthenticationDetails utvider WebAuthenticationDetails {private String verificationCode; offentlige CustomWebAuthenticationDetails (HttpServletRequest forespørsel) {super (forespørsel); verificationCode = request.getParameter ("kode"); } public String getVerificationCode () {return verificationCode; }}
Og vår sikkerhetskonfigurasjon:
@Configuration @EnableWebSecurity offentlig klasse LssSecurityConfig utvider WebSecurityConfigurerAdapter {@Autowired private CustomWebAuthenticationDetailsSource authenticationDetailsSource; @ Override beskyttet ugyldig konfigurasjon (HttpSecurity http) kaster unntak {http.formLogin () .authenticationDetailsSource (authenticationDetailsSource) ...}}
Og til slutt legger du til den ekstra parameteren i påloggingsskjemaet vårt:
Bekreftelseskode for Google Authenticator
Merk: Vi må angi vår tilpassede AuthenticationDetailsSource i vår sikkerhetskonfigurasjon.
5. Tilpasset godkjenningsleverandør
Deretter trenger vi en tilpasset AuthenticationProvider for å håndtere ekstra parametervalidering:
offentlig klasse CustomAuthenticationProvider utvider DaoAuthenticationProvider {@Autowired private UserRepository userRepository; @Override public Authentication authenticate (Authentication auth) kaster AuthenticationException {String verificationCode = ((CustomWebAuthenticationDetails) auth.getDetails ()) .getVerificationCode (); Brukerbruker = userRepository.findByEmail (auth.getName ()); if ((user == null)) {throw new BadCredentialsException ("Ugyldig brukernavn eller passord"); } hvis (user.isUsing2FA ()) {Totp totp = ny Totp (user.getSecret ()); if (! isValidLong (verificationCode) ||! totp.verify (verificationCode)) {throw new BadCredentialsException ("Ugyldig verfication code"); }} Autentiseringsresultat = super.authenticate (auth); returner nytt UsernamePasswordAuthenticationToken (bruker, result.getCredentials (), result.getAuthorities ()); } privat boolsk isValidLong (strengkode) {prøv {Long.parseLong (kode); } fange (NumberFormatException e) {return false; } returner sant; } @Override public boolean supports (Class authentication) {return authentication.equals (UsernamePasswordAuthenticationToken.class); }}
Merk at - etter at vi har bekreftet bekreftelseskoden for engangspassord, delegerte vi bare autentisering nedstrøms.
Her er vår Authentication Provider-bønne
@Bean offentlig DaoAuthenticationProvider authProvider () {CustomAuthenticationProvider authProvider = ny CustomAuthenticationProvider (); authProvider.setUserDetailsService (userDetailsService); authProvider.setPasswordEncoder (koder ()); return authProvider; }
6. Registreringsprosess
Nå, for at brukere skal kunne bruke applikasjonen til å generere tokens, må de sette opp ting riktig når de registrerer seg.
Og så må vi gjøre noen få enkle endringer i registreringsprosessen - for å la brukere som har valgt å bruke totrinnsbekreftelse, skann QR-koden de trenger for å logge inn senere.
Først legger vi til denne enkle innspillingen i registreringsskjemaet:
Bruk totrinnsbekreftelse
Så, i vår RegistrationController - vi omdirigerer brukere basert på deres valg etter bekreftelse av registreringen:
@GetMapping ("/ registrationConfirm") offentlig Strengbekreftelsesregistrering (@RequestParam ("token") Strengetoken, ...) {Stringresultat = userService.validateVerificationToken (token); hvis (result.equals ("valid")) {User user = userService.getUser (token); hvis (user.isUsing2FA ()) {model.addAttribute ("qr", userService.generateQRUrl (bruker)); return "redirect: /qrcode.html? lang =" + locale.getLanguage (); } model.addAttribute ("melding", messages.getMessage ("melding.kontoVerifisert", null, sted)); returner "redirect: / login? lang =" + locale.getLanguage (); } ...}
Og her er metoden vår generereQRUrl ():
offentlig statisk streng QR_PREFIX = "//chart.googleapis.com/chart?chs=200x200&chld=M%%7C0&cht=qr&chl="; @ Overstyr offentlig streng generereQRUrl (brukerbruker) {return QR_PREFIX + URLEncoder.encode (String.format ("otpauth: // totp /% s:% s? Secret =% s & issuer =% s", APP_NAME, user.getEmail () , user.getSecret (), APP_NAME), "UTF-8"); }
Og her er vår qrcode.html:
Skann denne strekkoden ved hjelp av Google Authenticator-appen på telefonen din for å bruke den senere ved pålogging
Gå til påloggingssiden
Noter det:
- generereQRUrl () metoden brukes til å generere QR-kode URL
- Denne QR-koden vil bli skannet av brukerens mobiltelefoner ved hjelp av Google Authenticator-appen
- Appen genererer en sekssifret kode som er gyldig i bare 30 sekunder, som er ønsket bekreftelseskode
- Denne bekreftelseskoden vil bli bekreftet mens du logger på med vår tilpassede AuthenticationProvider
7. Aktiver totrinnsbekreftelse
Deretter vil vi sørge for at brukere når som helst kan endre innloggingsinnstillingene sine - som følger:
@PostMapping ("/ user / update / 2fa") public GenericResponse modifyUser2FA (@RequestParam ("use2FA") boolean use2FA) kaster UnsupportedEncodingException {User user = userService.updateUser2FA (use2FA); if (use2FA) {return new GenericResponse (userService.generateQRUrl (user)); } returner null; }
Og her er updateUser2FA ():
@ Override offentlig brukeroppdatering User2FA (boolsk use2FA) {Authentication curAuth = SecurityContextHolder.getContext (). GetAuthentication (); User currentUser = (User) curAuth.getPrincipal (); currentUser.setUsing2FA (use2FA); currentUser = repository.save (currentUser); Authentication auth = new UsernamePasswordAuthenticationToken (currentUser, currentUser.getPassword (), curAuth.getAuthorities ()); SecurityContextHolder.getContext (). SetAuthentication (auth); returstrøm Bruker; }
Og her er frontend:
Du bruker totrinns autentisering Deaktiver 2FA Du bruker ikke totrinns autentisering Aktiver 2FASkann denne strekkoden med Google Authenticator-appen på telefonen din
function enable2FA () {set2FA (true); } funksjon disable2FA () {set2FA (false); } funksjon set2FA (use2FA) {$ .post ("/ user / update / 2fa", {use2FA: use2FA}, function (data) {if (use2FA) {$ ("# qr"). append (''). vis ();} annet {window.location.reload ();}}); }
8. Konklusjon
I denne raske opplæringen illustrerte vi hvordan du utfører en tofaktorautentiseringsimplementering ved hjelp av en Soft Token med Spring Security.
Hele kildekoden finner du - som alltid - over på GitHub.