Noah
5b6712ea97
* Legacy-importer tool updates the DB primary key serial after migrating the posts, to be max(posts.id)+1 -- especially important for PostgreSQL and MySQL (SQLite3 correctly picked the next ID by default?) * Add blog archive page and RSS, Atom and JSON feeds for the blog. URLs are /blog.rss, /blog.atom and /blog.json
96 lines
2.6 KiB
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)
|
|
}
|