הרשמה - הפעל חשבון חדש בדוא"ל

מאמר זה הוא חלק מסדרה: • מדריך רישום אבטחה באביב

• תהליך ההרשמה עם אבטחת אביב

• רישום - הפעל חשבון חדש בדוא"ל (מאמר נוכחי) • רישום אבטחה באביב - שלח שוב דוא"ל אימות

• הרשמה באבטחת אביב - קידוד סיסמאות

• ממשק ה- API לרישום הופך ל- RESTful

• אבטחת אביב - אפס את הסיסמה שלך

• רישום - חוזק סיסמא וכללים

• עדכון הסיסמה שלך

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

מאמר זה ממשיך את המתמשך הרשמה באביב ביטחון סִדרָה עם אחד החלקים החסרים של תהליך ההרשמה - אימות דוא"ל המשתמש לאישור חשבונו.

מנגנון אישור הרישום מאלץ את המשתמש להגיב ל- "אשר הרשמהדוא"ל שנשלח לאחר ההרשמה המוצלחת כדי לאמת את כתובת הדוא"ל שלו ולהפעיל את חשבונם. המשתמש עושה זאת על ידי לחיצה על קישור הפעלה ייחודי שנשלח אליו בדוא"ל.

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

2. אסימון אימות

נשתמש באסימון אימות פשוט כחפץ המפתח דרכו מאומת משתמש.

2.1. ה VerificationToken יֵשׁוּת

ה VerificationToken על הישות לעמוד בקריטריונים הבאים:

  1. זה חייב להתקשר חזרה ל מִשׁתַמֵשׁ (דרך יחס חד כיווני)
  2. היא תיווצר מיד לאחר ההרשמה
  3. זה יהיה תפוג תוך 24 שעות בעקבות יצירתו
  4. יש ייחודי, שנוצר באופן אקראי ערך

דרישות 2 ו -3 הן חלק מהגיון הרישום. השניים האחרים מיושמים בפשטות VerificationToken ישות כמו זו שבדוגמא 2.1:

דוגמא 2.1.

@Entity Class Class VerificationToken {סופי פרטי סטטי int EXPIRATION = 60 * 24; @Id @GeneratedValue (אסטרטגיה = GenerationType.AUTO) מזהה פרטי ארוך; אסימון מחרוזת פרטי; @OneToOne (targetEntity = User.class, fetch = FetchType.EAGER) @JoinColumn (nullable = false, name = "user_id") משתמש משתמש פרטי; תאריך תפוגה פרטי תאריך פרטי; תאריך פרטי calcExExyDate (int expiryTimeInMinutes) {לוח שנה cal = Calendar.getInstance (); cal.setTime (חותמת זמן חדשה (cal.getTime (). getTime ())); cal.add (Calendar.MINUTE, expiryTimeInMinutes); להחזיר תאריך חדש (cal.getTime (). getTime ()); } // בונים סטנדרטיים, גטרים וקובעים}

שים לב ל בטל = שקר על המשתמש כדי להבטיח שלמות נתונים ועקביות במערכת VerificationToken <->מִשׁתַמֵשׁ אִרגוּן.

2.2. תוסיף את ה מופעלת שדה ל מִשׁתַמֵשׁ

בתחילה, כאשר מִשׁתַמֵשׁ רשום, זה מופעלת שדה יוגדר ל שֶׁקֶר. במהלך תהליך אימות החשבון - אם יצליח - הוא יהפוך נָכוֹן.

בואו נתחיל בהוספת השדה ל מִשׁתַמֵשׁ יֵשׁוּת:

משתמש בכיתה ציבורית {... @Column (name = "enabled") מופעל בוליאני פרטי; משתמש ציבורי () {סופר (); this.enabled = false; } ...}

שים לב כיצד הגדרנו גם את ערך ברירת המחדל של שדה זה שֶׁקֶר.

3. במהלך רישום החשבון

בואו נוסיף שתי חלקים נוספים של לוגיקה עסקית למקרה השימוש ברישום המשתמשים:

  1. צור את VerificationToken עבור המשתמש והתמיד בו
  2. שלח את הודעת הדוא"ל לאישור החשבון - הכולל קישור אישור עם ה- VerificationToken ערך

3.1. שימוש באירוע אביב ליצירת האסימון ושליחת דוא"ל האימות

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

הבקר יפרסם אביב ApplicationEvent כדי להפעיל את ביצוע המשימות הללו. זה פשוט כמו להזריק את ApplicationEventPublisher ולאחר מכן להשתמש בו כדי לפרסם את השלמת ההרשמה.

דוגמא 3.1. מראה את ההיגיון הפשוט הזה:

דוגמא 3.1.

@Autowired ApplicationEventPublisher eventPublisher @PostMapping ("/ user / registration") public ModelAndView registerUserAccount (@ModelAttribute ("user") @ Valid UserDto userDto, HttpServletRequest בקשה, שגיאות שגיאה) {נסה {משתמש רשום = userService.registerNewUserA משתמש מחרוזת appUrl = request.getContextPath (); eventPublisher.publishEvent (OnRegistrationCompleteEvent חדש (רשום, request.getLocale (), appUrl)); } לתפוס (UserAlreadyExistException uaeEx) {ModelAndView mav = ModelAndView חדש ("רישום", "משתמש", userDto); mav.addObject ("הודעה", "חשבון לשם המשתמש / הדוא"ל הזה כבר קיים."); החזר mav; } לתפוס (RuntimeException לשעבר) {להחזיר ModelAndView חדש ("emailError", "user", userDto); } להחזיר ModelAndView חדש ("successRegister", "user", userDto); }

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

3.2. האירוע והמאזין

בואו נראה עכשיו את היישום בפועל של חדש זה OnRegistrationCompleteEvent שהבקר שלנו שולח, כמו גם המאזין שהולך לטפל בזה:

דוגמא 3.2.1. - ה OnRegistrationCompleteEvent

מחלקה ציבורית OnRegistrationCompleteEvent מרחיב את ApplicationEvent {private String appUrl; אזור מקומי פרטי; משתמש פרטי פרטי; OnRegistrationCompleteEvent ציבורי (משתמש משתמש, אזור מקומי, מחרוזת appUrl) {סופר (משתמש); this.user = משתמש; this.locale = אזור; this.appUrl = appUrl; } // גטרים וקובעים סטנדרטיים}

דוגמא 3.2.2. רישום האזנה מטפל ב OnRegistrationCompleteEvent

@Component בכיתה ציבורית RegistrationListener מיישם את ApplicationListener {@ שירות פרטי IUserService פרטי; @ הודעות פרטיות של MessageSource פרטיות; @MailSender פרטית אוטומטית של JavaMailSender; @ ביטול חלל ציבורי ב- ApplicationEvent (אירוע OnRegistrationCompleteEvent) {this.confirmRegistration (אירוע); } בטל פרטי אושר רישום (אירוע OnRegistrationCompleteEvent) {משתמש משתמש = event.getUser (); אסימון מחרוזת = UUID.randomUUID (). ToString (); service.createVerificationToken (משתמש, אסימון); מחרוזת recipientAddress = user.getEmail (); נושא מחרוזת = "אישור הרשמה"; מחרוזת confirmUrl = event.getAppUrl () + "/regitrationConfirm.html?token=" + אסימון; הודעת מחרוזת = messages.getMessage ("message.regSucc", null, event.getLocale ()); דוא"ל SimpleMailMessage = SimpleMailMessage חדש (); email.setTo (recipientAddress); email.setSubject (נושא); email.setText (הודעה + "\ r \ n" + "// localhost: 8080" + confirmUrl); mailSender.send (דוא"ל); }}

הנה ה אשר הרשמה השיטה תקבל את OnRegistrationCompleteEvent, לחלץ את כל הדרוש מִשׁתַמֵשׁ מידע ממנו, צור את אסימון האימות, המשך אותו ואז שלח אותו כפרמטר בסעיף "אשר הרשמה" קישור.

כאמור לעיל, כל אחד מהם javax.mail.AuthenticationFailedException נזרק על ידי JavaMailSender יטופל על ידי הבקר.

3.3. עיבוד פרמטר אסימון האימות

כאשר המשתמש מקבל את "אשר הרשמההקישור הם צריכים ללחוץ עליו.

ברגע שהם עושים זאת - הבקר יחלץ את הערך של הפרמטר האסימון בבקשת ה- GET שהתקבלה וישתמש בו כדי לאפשר את ה- מִשׁתַמֵשׁ.

בואו נראה את התהליך הזה בדוגמה 3.3.1:

דוגמא 3.3.1. - RegistrationController עיבוד אישור ההרשמה

@ שירות פרטי IUserService אוטומטי; @GetMapping ("/ regitrationConfirm") ציבורי מחרוזת confirmRegistration (בקשת WebRequest, מודל מודל, @RequestParam ("אסימון") אסימון מחרוזת) {אזור מקומי = request.getLocale (); VerificationToken verificationToken = service.getVerificationToken (אסימון); if (verificationToken == null) {מחרוזת הודעה = messages.getMessage ("auth.message.invalidToken", null, locale); model.addAttribute ("הודעה", הודעה); להחזיר "redirect: /badUser.html? lang =" + locale.getLanguage (); } משתמש משתמש = verificationToken.getUser (); לוח שנה cal = Calendar.getInstance (); אם ((verificationToken.getExpiryDate (). getTime () - cal.getTime (). getTime ()) <= 0) {String messageValue = messages.getMessage ("auth.message.expired", null, locale) model.addAttribute ("הודעה", messageValue); להחזיר "redirect: /badUser.html? lang =" + locale.getLanguage (); } user.setEnabled (נכון); service.saveRegisteredUser (משתמש); להחזיר "redirect: /login.html? lang =" + request.getLocale (). getLanguage (); }

המשתמש ינותב לדף שגיאה עם ההודעה המתאימה אם:

  1. ה VerificationToken לא קיים, משום מה או
  2. ה VerificationToken פג תוקף

ראה דוגמה 3.3.2. כדי לראות את דף השגיאה.

דוגמא 3.3.2. - ה badUser.html

כפי שאנו רואים, עכשיו MyUserDetailsService לא משתמש ב מופעלת דגל המשתמש - וכך זה יאפשר רק לאפשר למשתמש לאמת.

כעת נוסיף AuthenticationFailureHandler כדי להתאים אישית את ההודעות החריגות שמקורן MyUserDetailsService. שֶׁלָנוּ CustomAuthenticationFailureHandler מוצג בדוגמה 4.2.:

דוגמה 4.2. - CustomAuthenticationFailureHandler:

מחלקה ציבורית @Component CustomAuthenticationFailureHandler מרחיב SimpleUrlAuthenticationFailureHandler {@Autowired הודעות MessageSource פרטיות; @ LocaleResolver פרטית אוטומטית localeResolver; @ ביטול חלל ציבורי ב- AuthenticationFailure (בקשת HttpServletRequest, תגובה HttpServletResponse, AuthenticationException) זורק IOException, ServletException {setDefaultFailureUrl ("/ login.html? Error = true"); super.onAuthenticationFailure (בקשה, תגובה, חריג); אזור מקומי = localeResolver.resolveLocale (בקשה); מחרוזת errorMessage = messages.getMessage ("message.badCredentials", null, locale); אם (exception.getMessage (). equalsIgnoreCase ("המשתמש מושבת")) {errorMessage = messages.getMessage ("auth.message.disabled", null, locale); } אחרת אם (exception.getMessage (). equalsIgnoreCase ("חשבון המשתמש פג תוקפו")) {errorMessage = messages.getMessage ("auth.message.expired", null, locale); } request.getSession (). setAttribute (WebAttributes.AUTHENTICATION_EXCEPTION, errorMessage); }}

נצטרך לשנות login.html כדי להציג את הודעות השגיאה.

דוגמה 4.3. - הצג הודעות שגיאה בשעה login.html:

 שְׁגִיאָה 

5. התאמת שכבת ההתמדה

בואו כעת נספק את היישום בפועל של חלק מהפעולות הללו הכוללות את אסימון האימות, כמו גם את המשתמשים.

נסקור:

  1. חדש VerificationTokenRepository
  2. שיטות חדשות ב ממשק משתמש והטמעתו לצורך פעולות CRUD חדשות

דוגמאות 5.1 - 5.3. הראה את הממשקים והיישום החדשים:

דוגמה 5.1. - ה VerificationTokenRepository

ממשק ציבורי VerificationTokenRepository מרחיב את JpaRepository {VerificationToken findByToken (אסימון מחרוזת); VerificationToken findByUser (משתמש משתמש); }

דוגמה 5.2. - ה IUserService מִמְשָׁק

ממשק ציבורי IUserService {משתמש registerNewUserAccount (UserDto userDto) זורק UserAlreadyExistException; משתמש getUser (מחרוזת verificationToken); בטל saveRegisteredUser (משתמש משתמש); בטל createVerificationToken (משתמש משתמש, אסימון מחרוזת); VerificationToken getVerificationToken (מחרוזת VerificationToken); }

דוגמה 5.3. ה שירות משתמש

@Service @Transactional public class UserService מיישם את IUserService {@ מאגר UserRepository פרטי; @Autowired פרטי VerificationTokenRepository tokenRepository; @Override משתמש ציבורי registerNewUserAccount (UserDto userDto) זורק UserAlreadyExistException {if (emailExist (userDto.getEmail ())) {זרוק UserAlreadyExistException חדש ("יש חשבון עם כתובת הדוא"ל הזו:" + userDto.getEmail ()); } משתמש משתמש = משתמש חדש (); user.setFirstName (userDto.getFirstName ()); user.setLastName (userDto.getLastName ()); user.setPassword (userDto.getPassword ()); user.setEmail (userDto.getEmail ()); user.setRole (תפקיד חדש (Integer.valueOf (1), משתמש)); להחזיר repository.save (משתמש); } אימייל בוליאני פרטיExist (מייל מחרוזת) {return userRepository.findByEmail (email)! = null; } @Override משתמש ציבורי getUser (מחרוזת verificationToken) {משתמש משתמש = tokenRepository.findByToken (verificationToken) .getUser (); משתמש חוזר; } @Override VerificationToken ציבורי getVerificationToken (מחרוזת VerificationToken) {החזר tokenRepository.findByToken (VerificationToken); } @ ביטול חלל ציבורי saveRegisteredUser (משתמש משתמש) {repository.save (user); } @ ביטול ריק ריק ציבורי createVerificationToken (משתמש משתמש, אסימון מחרוזת) {VerificationToken myToken = VerificationToken חדש (אסימון, משתמש); tokenRepository.save (myToken); }}

6. מסקנה

במאמר זה הרחבנו את תהליך הרישום לכלול הליך הפעלת חשבון בדוא"ל.

לוגיקת הפעלת החשבון מחייבת שליחת אסימון אימות למשתמש בדוא"ל בכדי שיוכלו לשלוח אותו בחזרה לבקר כדי לאמת את זהותו.

את היישום של מדריך ההרשמה עם Spring Security ניתן למצוא בפרויקט GitHub - זהו פרויקט מבוסס Eclipse, כך שיהיה קל לייבא ולהפעיל אותו כפי שהוא.

הַבָּא » רישום אבטחה באביב - שלח שוב דוא"ל אימות « קודם תהליך ההרשמה עם אבטחת אביב

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