هدایت کاربر به درستی پس از ورود به سیستم (Redirect User Appropriately After Login)
اگر یک کاربر غیرمجاز (Unauthenticated User) سعی کند به GET /account/view دسترسی پیدا کند، به صفحه ورود (Login Page) هدایت میشود. سپس پس از ورود موفقیتآمیز (Successful Login)، به فرم (Form) GET /snippet/create هدایت میشود. این برای کاربر گیجکننده و نامناسب است، زیرا در صفحهای متفاوت از جایی که در ابتدا میخواستند بروند، قرار میگیرند.
هدف شما در این تمرین این است که برنامه (Application) را بهروزرسانی کنید تا کاربران پس از ورود به صفحه مورد نظر (Target Page) که در ابتدا میخواستند به آن بروند، هدایت شوند.
مرحله 1 (Step 1)
میانافزار (Middleware) requireAuthentication() را بهروزرسانی کنید تا قبل از اینکه یک کاربر غیرمجاز به صفحه ورود هدایت شود، مسیر URL (URL Path) که سعی در دسترسی به آن دارند به دادههای جلسه (Session Data) آنها اضافه شود.
مرحله 2 (Step 2)
مدیریتکننده (Handler) userLogin را بهروزرسانی کنید تا پس از ورود موفقیتآمیز کاربر، دادههای جلسه کاربر را برای مسیر URL بررسی کند. اگر وجود دارد، آن را از دادههای جلسه حذف کرده و کاربر را به آن مسیر URL هدایت کنید. در غیر این صورت، بهطور پیشفرض (Default) کاربر را به /snippet/create هدایت کنید.
کد پیشنهادی
کد پیشنهادی برای مرحله 1
package main ... func (app *application) requireAuthentication(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if !app.isAuthenticated(r) { // Add the path that the user is trying to access to their session // data. app.sessionManager.Put(r.Context(), "redirectPathAfterLogin", r.URL.Path) http.Redirect(w, r, "/user/login", http.StatusSeeOther) return } w.Header().Add("Cache-Control", "no-store") next.ServeHTTP(w, r) }) } ...
کد پیشنهادی برای مرحله 2
package main ... func (app *application) userLoginPost(w http.ResponseWriter, r *http.Request) { var form userLoginForm err := app.decodePostForm(r, &form) if err != nil { app.clientError(w, http.StatusBadRequest) return } form.CheckField(validator.NotBlank(form.Email), "email", "This field cannot be blank") form.CheckField(validator.Matches(form.Email, validator.EmailRX), "email", "This field must be a valid email address") form.CheckField(validator.NotBlank(form.Password), "password", "This field cannot be blank") if !form.Valid() { data := app.newTemplateData(r) data.Form = form app.render(w, r, http.StatusUnprocessableEntity, "login.tmpl", data) return } id, err := app.users.Authenticate(form.Email, form.Password) if err != nil { if errors.Is(err, models.ErrInvalidCredentials) { form.AddNonFieldError("Email or password is incorrect") data := app.newTemplateData(r) data.Form = form app.render(w, r, http.StatusUnprocessableEntity, "login.tmpl", data) } else { app.serverError(w, r, err) } return } err = app.sessionManager.RenewToken(r.Context()) if err != nil { app.serverError(w, r, err) return } app.sessionManager.Put(r.Context(), "authenticatedUserID", id) // Use the PopString method to retrieve and remove a value from the session // data in one step. If no matching key exists this will return the empty // string. path := app.sessionManager.PopString(r.Context(), "redirectPathAfterLogin") if path != "" { http.Redirect(w, r, path, http.StatusSeeOther) return } http.Redirect(w, r, "/snippet/create", http.StatusSeeOther) } ...