package authentication import ( "context" "errors" "net/http" "git.kirsle.net/apps/gophertype/pkg/console" "git.kirsle.net/apps/gophertype/pkg/models" "git.kirsle.net/apps/gophertype/pkg/session" ) // CurrentUser returns the currently logged-in user in the browser session. func CurrentUser(r *http.Request) (models.User, error) { sess := session.Get(r) if loggedIn, ok := sess.Values["logged-in"].(bool); ok && loggedIn { id := sess.Values["user-id"].(int) user, err := models.GetUserByID(id) return user, err } return models.User{}, errors.New("not logged in") } // Login logs the browser session in as the user. func Login(w http.ResponseWriter, r *http.Request, user models.User) { sess := session.Get(r) sess.Values["logged-in"] = true sess.Values["user-id"] = int(user.ID) if err := sess.Save(r, w); err != nil { console.Error("Login() Session error: " + err.Error()) } } // Logout logs the current user out. func Logout(w http.ResponseWriter, r *http.Request) { sess := session.Get(r) sess.Values["logged-in"] = false sess.Values["user-id"] = 0 sess.Save(r, w) } // LoggedIn returns whether the session is logged in as a user. func LoggedIn(r *http.Request) bool { sess := session.Get(r) if v, ok := sess.Values["logged-in"].(bool); ok && v == true { return true } return false } // LoginRequired is a middleware for authenticated endpoints. func LoginRequired(next http.Handler) http.Handler { middleware := func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() if user, ok := ctx.Value(session.UserKey).(models.User); ok { if user.ID > 0 { next.ServeHTTP(w, r) return } } // Redirect to the login page. w.Header().Set("Location", "/login?next="+r.URL.Path) w.WriteHeader(http.StatusFound) } return http.HandlerFunc(middleware) } // Middleware checks the authentication and loads the user onto the request context. func Middleware(next http.Handler) http.Handler { middleware := func(w http.ResponseWriter, r *http.Request) { user, err := CurrentUser(r) if err != nil { // User not logged in, go to next middleware. next.ServeHTTP(w, r) return } // Put the CurrentUser into the request context. ctx := context.WithValue(r.Context(), session.UserKey, user) next.ServeHTTP(w, r.WithContext(ctx)) } return http.HandlerFunc(middleware) }