gophertype/pkg/authentication/login.go

96 lines
2.6 KiB
Go

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 {
if id, ok := sess.Values["user-id"].(int); ok && id > 0 {
user, err := models.Users.GetUserByID(id)
if err != nil {
console.Error("CurrentUser: user '%d' was not found in DB! Logging out the session", id)
delete(sess.Values, "user-id")
delete(sess.Values, "logged-in")
return user, err
}
return user, err
}
return models.User{}, errors.New("not logged in")
}
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)
}