Dvojfaktorové overenie s jarnou bezpečnosťou
1. Prehľad
V tomto výučbe budeme implementovať funkčnosť dvojfaktorového overovania pomocou mäkkého tokenu a jarnej bezpečnosti.
Budeme pridávať nové funkcie do existujúceho jednoduchého toku prihlásenia a na generovanie tokenov použijeme aplikáciu Google Authenticator.
Zjednodušene povedané, dvojfaktorová autentifikácia je proces overovania, ktorý sa riadi dobre známym princípom „niečo, čo užívateľ vie, a niečo, čo užívateľ má“.
Používatelia teda počas autentifikácie poskytujú ďalší „overovací token“ - jednorazový kód na overenie hesla založený na algoritme Time-based One-time Password TOTP.
2. Konfigurácia Maven
Najskôr, aby sme mohli aplikáciu Google Authenticator používať v našej aplikácii, musíme:
- Vygenerujte tajný kľúč
- Poskytnite používateľovi tajný kľúč prostredníctvom QR kódu
- Pomocou tohto tajného kľúča overte token zadaný používateľom.
Použijeme jednoduchú knižnicu na strane servera na vygenerovanie / overenie jednorazového hesla pridaním nasledujúcej závislosti do našej pom.xml:
org.jboss.aerogear aerogear-otp-java 1.0.0
3. Entita používateľa
Ďalej upravíme našu používateľskú entitu tak, aby obsahovala ďalšie informácie, a to nasledovne:
@Entity verejná trieda Používateľ {... private boolean isUsing2FA; súkromné reťazcové tajomstvo; public User () {super (); this.secret = Base32.random (); ...}}
Poznač si to:
- Ukladáme náhodný tajný kód pre každého používateľa, ktorý sa použije neskôr pri generovaní overovacieho kódu
- Naše dvojstupňové overenie je voliteľné
4. Extra parameter prihlásenia
Najskôr budeme musieť upraviť našu konfiguráciu zabezpečenia tak, aby akceptovala ďalší parameter - overovací token. To môžeme dosiahnuť použitím zvyku AuthenticationDetailsSource:
Tu je náš CustomWebAuthenticationDetailsSource:
@ Verejná trieda komponentu CustomWebAuthenticationDetailsSource implementuje AuthenticationDetailsSource {@Override public WebAuthenticationDetails buildDetails (kontext HttpServletRequest) {vrátiť nový CustomWebAuthenticationDetails (kontext); }}
a tu je CustomWebAuthenticationDetails:
verejná trieda CustomWebAuthenticationDetails rozširuje WebAuthenticationDetails {private String verificationCode; public CustomWebAuthenticationDetails (požiadavka HttpServletRequest) {super (požiadavka); verificationCode = request.getParameter ("kód"); } public String getVerificationCode () {návrat overovací kód; }}
A naša konfigurácia zabezpečenia:
@Configuration @EnableWebSecurity verejná trieda LssSecurityConfig rozširuje WebSecurityConfigurerAdapter {@Autowired private CustomWebAuthenticationDetailsSource authenticationDetailsSource; @Override protected void configure (HttpSecurity http) vyvolá výnimku {http.formLogin () .authenticationDetailsSource (authenticationDetailsSource) ...}}
A nakoniec pridajte ďalší parameter do nášho prihlasovacieho formulára:
Verifikačný kód aplikácie Google Authenticator
Poznámka: Musíme nastaviť náš zvyk AuthenticationDetailsSource v našej konfigurácii zabezpečenia.
5. Vlastný poskytovateľ autentifikácie
Ďalej budeme potrebovať zvyk AuthenticationProvider na spracovanie overenia ďalších parametrov:
verejná trieda CustomAuthenticationProvider rozširuje DaoAuthenticationProvider {@Autowired private UserRepository userRepository; @Override public Authentication authenticate (Authentication auth) throws AuthenticationException {String verificationCode = ((CustomWebAuthenticationDetails) auth.getDetails ()) .getVerificationCode (); Používateľ user = userRepository.findByEmail (auth.getName ()); if ((user == null)) {throw new BadCredentialsException ("Invalid username or password"); } if (user.isUsing2FA ()) {Totp totp = nový Totp (user.getSecret ()); if (! isValidLong (verificationCode) ||! totp.verify (verificationCode)) {throw new BadCredentialsException ("Invalid verfication code"); }} Výsledok autentifikácie = super.authenticate (auth); vrátiť nové UsernamePasswordAuthenticationToken (user, result.getCredentials (), result.getAuthorities ()); } private boolean isValidLong (reťazcový kód) {try {Long.parseLong (kód); } catch (NumberFormatException e) {return false; } návrat pravdivý; } @Override public boolean podporuje (autentifikácia triedy) {návrat autentifikácie.equals (UsernamePasswordAuthenticationToken.class); }}
Upozorňujeme, že - keď sme overili jednorazový overovací kód hesla, jednoducho sme delegovali autentifikáciu po prúde.
Tu je naša fazuľa poskytovateľa autentifikácie
@Bean public DaoAuthenticationProvider authProvider () {CustomAuthenticationProvider authProvider = nový CustomAuthenticationProvider (); authProvider.setUserDetailsService (userDetailsService); authProvider.setPasswordEncoder (encoder ()); návrat authProvider; }
6. Proces registrácie
Teraz, aby používatelia mohli používať aplikáciu na generovanie tokenov, budú musieť pri registrácii správne nastaviť veci.
Budeme teda musieť urobiť niekoľko jednoduchých úprav procesu registrácie - aby sme používateľom, ktorí sa rozhodli použiť dvojstupňové overenie, umožnili naskenujte QR kód, ktorý potrebujú na neskoršie prihlásenie.
Najskôr pridáme tento jednoduchý vstup do nášho registračného formulára:
Použite dvojstupňové overenie
Potom v našom RegistrationController - používateľov presmerujeme na základe ich výberu po potvrdení registrácie:
@GetMapping ("/ registrationConfirm") public String confirmRegistration (@RequestParam ("token") String token, ...) {String result = userService.validateVerificationToken (token); if (result.equals ("valid")) {User user = userService.getUser (token); if (user.isUsing2FA ()) {model.addAttribute ("qr", userService.generateQRUrl (užívateľ)); return "redirect: /qrcode.html? lang =" + locale.getLanguage (); } model.addAttribute ("správa", messages.getMessage ("message.accountVerified", null, miestne nastavenie)); return "redirect: / login? lang =" + locale.getLanguage (); } ...}
A tu je naša metóda generateQRUrl ():
verejný statický reťazec QR_PREFIX = "//chart.googleapis.com/chart?chs=200x200&chld=M%%7C0&cht=qr&chl="; @Override public String generateQRUrl (užívateľský užívateľ) {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“); }
A tu je náš qrcode.html:
Naskenujte tento čiarový kód pomocou aplikácie Google Authenticator na telefóne, aby ste ho mohli neskôr použiť pri prihlasovaní
Prejdite na prihlasovaciu stránku
Poznač si to:
- generateQRUrl () metóda sa používa na generovanie URL kódu QR
- Tento QR kód naskenujú používatelia mobilných telefónov pomocou aplikácie Google Authenticator
- Aplikácia vygeneruje šesťmiestny kód, ktorý je platný iba 30 sekúnd, čo je požadovaný overovací kód
- Tento verifikačný kód bude overený pri prihlásení pomocou nášho zvyku AuthenticationProvider
7. Povolte dvojstupňové overenie
Ďalej zaistíme, aby používatelia mohli kedykoľvek zmeniť svoje predvoľby prihlásenia - a to nasledovne:
@PostMapping ("/ user / update / 2fa") public GenericResponse modifyUser2FA (@RequestParam ("use2FA") boolean use2FA) hodí UnsupportedEncodingException {User user = userService.updateUser2FA (use2FA); if (use2FA) {return new GenericResponse (userService.generateQRUrl (user)); } return null; }
A tu je updateUser2FA ():
@Override public User updateUser2FA (boolean use2FA) {Authentication curAuth = SecurityContextHolder.getContext (). GetAuthentication (); Užívateľ currentUser = (Užívateľ) curAuth.getPrincipal (); currentUser.setUsing2FA (use2FA); currentUser = repository.save (currentUser); Autentifikácia auth = nové UsernamePasswordAuthenticationToken (currentUser, currentUser.getPassword (), curAuth.getAuthorities ()); SecurityContextHolder.getContext (). SetAuthentication (auth); návratový prúdUser; }
A tu je front-end:
Používate dvojstupňové overenie Zakázať 2FA Nepoužívate dvojstupňové overenie Povoliť 2FANaskenujte tento čiarový kód pomocou aplikácie Google Authenticator v telefóne
funkcia enable2FA () {set2FA (true); } funkcia disable2FA () {set2FA (false); } function set2FA (use2FA) {$ .post ("/ user / update / 2fa", {use2FA: use2FA}, function (data) {if (use2FA) {$ ("# qr"). append (''). show ();} else {window.location.reload ();}}); }
8. Záver
V tomto rýchlom výučbe sme si ukázali, ako vykonať implementáciu dvojfaktorovej autentifikácie pomocou mäkkého tokenu s jarnou bezpečnosťou.
Celý zdrojový kód nájdete - ako vždy - na GitHub.