שני גורמי אישור עם אבטחת אביב

1. סקירה כללית

במדריך זה אנו מיישמים פונקציונליות של אימות שני גורמים באמצעות אסימון רך ואבטחת אביב.

אנו נוסיף את הפונקציונליות החדשה לזרימת כניסה פשוטה וקיימת ונשתמש באפליקציית המאמת של גוגל כדי ליצור את האסימונים.

במילים פשוטות, אימות שני גורמים הוא תהליך אימות העוקב אחר העיקרון הידוע של "משהו שהמשתמש יודע ומשהו שיש למשתמש".

וכך, משתמשים מספקים "אסימון אימות" נוסף במהלך האימות - קוד אימות סיסמא חד פעמי המבוסס על אלגוריתם TOTP סיסמא חד פעמי מבוסס זמן.

2. תצורת Maven

ראשית, על מנת להשתמש ב- Google Authenticator באפליקציה שלנו עלינו:

  • צור מפתח סודי
  • ספק מפתח סודי למשתמש באמצעות קוד QR
  • אמת את האסימון שהוזן על ידי המשתמש באמצעות מפתח סודי זה.

נשתמש בספריה פשוטה בצד השרת כדי ליצור / לאמת סיסמא חד פעמית על ידי הוספת התלות הבאה שלנו pom.xml:

 org.jboss.aerogear aerogear-otp-java 1.0.0 

3. ישות משתמשים

לאחר מכן, נשנה את ישות המשתמש שלנו כדי להחזיק מידע נוסף - כדלקמן:

משתמש בכיתה ציבורית @Entity {... בוליאני פרטי isUsing2FA; סוד מחרוזת פרטי; משתמש ציבורי () {סופר (); this.secret = Base32.random (); ...}}

ציין זאת:

  • אנו שומרים קוד סודי אקראי לכל משתמש שישמש מאוחר יותר ליצירת קוד אימות
  • האימות הדו-שלבי שלנו הוא אופציונלי

4. פרמטר כניסה נוסף

ראשית, נצטרך להתאים את תצורת האבטחה שלנו כדי לקבל פרמטר נוסף - אסימון אימות. אנו יכולים להשיג זאת על ידי שימוש בהתאמה אישית AuthenticationDetailsSource:

הנה שלנו CustomWebAuthenticationDetailsSource:

מחלקה ציבורית @Component CustomWebAuthenticationDetailsSource מיישם AuthenticationDetailsSource {@Override Public WebAuthenticationDetails buildDetails (HttpServletRequest context) {להחזיר CustomWebAuthenticationDetails חדש (הקשר); }}

והנה CustomWebAuthenticationDetails:

מחלקה ציבורית CustomWebAuthenticationDetails מרחיב את WebAuthenticationDetails {private String verificationCode; PublicWebAuthenticationDetails ציבורי (בקשת HttpServletRequest) {super (בקשה); verificationCode = request.getParameter ("קוד"); } ציבורי מחרוזת getVerificationCode () {return verificationCode; }}

ותצורת האבטחה שלנו:

@Configuration @EnableWebSecurity מחלקה ציבורית LssSecurityConfig מרחיב את WebSecurityConfigurerAdapter {@Autowired פרטי CustomWebAuthenticationDetailsSource authenticationDetailsSource; התצורה הריקה המוגנת על ידי @Override (HttpSecurity http) זורקת חריג {http.formLogin () .authenticationDetailsSource (authenticationDetailsSource) ...}}

ולבסוף הוסף את הפרמטר הנוסף לטופס הכניסה שלנו:

 קוד אימות מאמת גוגל 

הערה: עלינו להגדיר את המנהג שלנו AuthenticationDetailsSource בתצורת האבטחה שלנו.

5. ספק אימות מותאם אישית

לאחר מכן, נצטרך מותאם אישית אימות ספק לטיפול באימות פרמטרים נוסף:

מחלקה ציבורית CustomAuthenticationProvider מרחיב את DaoAuthenticationProvider {@Autowired פרטי UserRepository userRepository; @Override אימות אימות ציבורי (Authentication auth) זורק AuthenticationException {String verificationCode = ((CustomWebAuthenticationDetails) auth.getDetails ()) .getVerificationCode (); משתמש משתמש = userRepository.findByEmail (auth.getName ()); if ((user == null)) {throw new BadCredentialsException ("שם משתמש או סיסמה לא חוקיים"); } אם (user.isUsing2FA ()) {Totp totp = Totp חדש (user.getSecret ()); אם (! isValidLong (verificationCode) ||! totp.verify (verificationCode)) {זרוק BadCredentialsException חדש ("קוד אימות לא חוקי"); }} תוצאת אימות = super.authenticate (auth); להחזיר UsernamePasswordAuthenticationToken חדש (user, result.getCredentials (), result.getAuthorities ()); } בוליאני פרטי isValidLong (קוד מחרוזת) {נסה {Long.parseLong (קוד); } לתפוס (NumberFormatException e) {return false; } להחזיר נכון; } @Override תומך בוליאני ציבורי (אימות מחלקה) {להחזיר authentication.equals (UsernamePasswordAuthenticationToken.class); }}

שימו לב - לאחר שאימתנו את קוד אימות הסיסמה החד פעמי, פשוט האצנו אימות במורד הזרם.

הנה שעועית ספק האימות שלנו

@Bean הציבור DaoAuthenticationProvider authProvider () {CustomAuthenticationProvider authProvider = חדש CustomAuthenticationProvider (); authProvider.setUserDetailsService (userDetailsService); authProvider.setPasswordEncoder (מקודד ()); החזר authProvider; }

6. תהליך רישום

כעת, על מנת שמשתמשים יוכלו להשתמש ביישום ליצירת אסימונים, הם יצטרכו להגדיר את הדברים כראוי כאשר הם נרשמים.

וכך, נצטרך לבצע כמה שינויים פשוטים בתהליך הרישום - כדי לאפשר למשתמשים שבחרו להשתמש באימות דו-שלבי סרוק את קוד ה- QR הדרוש להם כדי להתחבר מאוחר יותר.

ראשית, אנו מוסיפים קלט פשוט זה לטופס ההרשמה שלנו:

השתמש באימות דו-שלבי 

ואז, שלנו RegistrationController - אנו מפנים משתמשים על פי בחירתם לאחר אישור ההרשמה:

@GetMapping ("/ registrationConfirm") ציבורי מחרוזת confirmRegistration (@RequestParam ("אסימון") אסימון מחרוזת, ...) {מחרוזת תוצאה = userService.validateVerificationToken (אסימון); אם (result.equals ("חוקי")) {משתמש משתמש = userService.getUser (אסימון); אם (user.isUsing2FA ()) {model.addAttribute ("qr", userService.generateQRUrl (user)); להחזיר "redirect: /qrcode.html? lang =" + locale.getLanguage (); } model.addAttribute ("הודעה", messages.getMessage ("message.accountVerified", null, locale)); להחזיר "redirect: / login? lang =" + locale.getLanguage (); } ...}

והנה השיטה שלנו createQRUrl ():

מחרוזת סטטית ציבורית QR_PREFIX = "//chart.googleapis.com/chart?chs=200x200&chld=M%%7C0&cht=qr&chl="; @ מעקף ציבורי ציבורי ליצור QRUrl (משתמש משתמש) {החזר QR_PREFIX + URLEncoder.encode (String.format ("otpauth: // totp /% s:% s? Secret =% s & issuer =% s", APP_NAME, user.getEmail ()) , user.getSecret (), APP_NAME), "UTF-8"); }

והנה שלנו qrcode.html:

סרוק ברקוד זה באמצעות אפליקציית Google Authenticator בטלפון שלך כדי להשתמש בו מאוחר יותר בכניסה

עבור לדף הכניסה

ציין זאת:

  • createQRUrl () השיטה משמשת ליצירת כתובת QR של קוד QR
  • קוד QR זה ייסרק על ידי משתמשים בטלפונים ניידים באמצעות אפליקציית המאמת של גוגל
  • האפליקציה תייצר קוד בן 6 ספרות שתקף למשך 30 שניות שהוא קוד האימות הרצוי
  • קוד אימות זה יאומת בזמן הכניסה באמצעות המותאם אישית שלנו אימות ספק

7. הפעל אימות דו שלבי

לאחר מכן, נדאג שמשתמשים יוכלו לשנות את העדפות הכניסה שלהם בכל עת - באופן הבא:

@PostMapping ("/ user / update / 2fa") ציבורי GenericResponse modifyUser2FA (@RequestParam ("use2FA") בוליאני use2FA) זורק UnupportedEncodingException {User user = userService.updateUser2FA (use2FA); אם (use2FA) {להחזיר GenericResponse חדש (userService.generateQRUrl (משתמש)); } להחזיר אפס; }

והנה updateUser2FA ():

@ עקוב אחר עדכון משתמש ציבורי User2FA (use2FA בוליאני) {Authentication curAuth = SecurityContextHolder.getContext (). GetAuthentication (); משתמש currentUser = (משתמש) curAuth.getPrincipal (); currentUser.setUsing2FA (use2FA); currentUser = repository.save (CurrentUser); אימות auth = new UsernamePasswordAuthenticationToken (currentUser, currentUser.getPassword (), curAuth.getAuthorities ()); SecurityContextHolder.getContext (). SetAuthentication (auth); החזר זרם משתמש; }

והנה החזית:

 אתה משתמש באימות דו-שלבי השבת 2FA אינך משתמש באימות דו-שלבי הפעל 2FA

סרוק ברקוד זה באמצעות אפליקציית המאמת של גוגל בטלפון שלך

פונקציה enable2FA () {set2FA (true); } פונקציה disable2FA () {set2FA (false); } פונקציה set2FA (use2FA) {$ .post ("/ user / update / 2fa", {use2FA: use2FA}, function (data) {if (use2FA) {$ ("# qr"). append (''). הצג ();} אחר {window.location.reload ();}}); }

8. מסקנה

במדריך מהיר זה, המחשנו כיצד לבצע יישום אימות דו-גורמי באמצעות Soft Token עם Spring Security.

קוד המקור המלא ניתן למצוא - כמו תמיד - ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found