Let's Go تمرین‌های راهنما › هدایت مناسب کاربر بعد از ورود
قبلی · فهرست · بعدی
فصل ۱۶.۵.

هدایت مناسب کاربر بعد از ورود

اگر یک کاربر احراز هویت نشده سعی کند از GET /account/view بازدید کند، به صفحه ورود هدایت می‌شود. سپس پس از ورود موفق، به فرم GET /snippet/create هدایت می‌شود. این برای کاربر ناخوشایند و گیج‌کننده است، چون در صفحه‌ای متفاوت از جایی که در ابتدا می‌خواستند بروند قرار می‌گیرند.

هدف شما در این تمرین به‌روزرسانی برنامه است تا کاربران به صفحه‌ای که در ابتدا سعی می‌کردند بازدید کنند بعد از ورود هدایت شوند.

مرحله 1

middleware requireAuthentication() را به‌روزرسانی کنید تا قبل از اینکه یک کاربر احراز هویت نشده به صفحه ورود هدایت شود، مسیر URL که سعی می‌کند بازدید کند به داده‌های نشست آن‌ها اضافه شود.

نمایش کد پیشنهادی

مرحله 2

handler userLogin را به‌روزرسانی کنید تا نشست کاربر را برای یک مسیر URL بعد از ورود موفق بررسی کند. اگر یکی وجود داشت، آن را از داده‌های نشست حذف کند و کاربر را به آن مسیر URL هدایت کند. در غیر این صورت، به طور پیش‌فرض کاربر را به /snippet/create هدایت کند.

نمایش کد پیشنهادی

کد پیشنهادی

کد پیشنهادی برای مرحله 1

File: cmd/web/middleware.go
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

File: cmd/web/handlers.go
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)
}

...