Logout and some event logging on auth

main
Drew Bednar 2 months ago
parent a50cb265cb
commit 4b2d729f4c

@ -389,6 +389,7 @@ func handleUserLoginPost(logger *slog.Logger, tc *TemplateCache, sm *scs.Session
id, err := userService.Authenticate(form.Email, form.Password)
if err != nil {
if errors.Is(err, model.ErrInvalidCredentials) {
logAuthFailure(logger, r, form.Email)
form.AddNonFieldError("Email or password is incorrect")
data := newTemplateData(r, sm)
@ -414,13 +415,32 @@ func handleUserLoginPost(logger *slog.Logger, tc *TemplateCache, sm *scs.Session
// Add the ID of the current user to the session, so that they are now "logged in"
sm.Put(r.Context(), "authenticatedUserID", id)
logAuthSuccess(logger, r, form.Email, id)
http.Redirect(w, r, "/snippet/create", http.StatusSeeOther)
})
}
func handleUserLogoutPost() http.Handler {
func handleUserLogoutPost(logger *slog.Logger, sm *scs.SessionManager) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Logout the user")
// Use RenewToken on the current session to change the session ID
err := sm.RenewToken(r.Context())
if err != nil {
serverError(w, r, err)
}
userId := sm.GetString(r.Context(), "authenticatedUserID")
if userId == "" {
logger.Info("No athenticated user in session")
} else {
logger.Info(fmt.Sprintf("Logging out user: %s", userId))
}
// Remove the authenticatedUserID from the session data
sm.Remove(r.Context(), "authenticatedUserID")
// Add a flash message
sm.Put(r.Context(), "flash", "You've been logged out successfully!")
http.Redirect(w, r, "/", http.StatusSeeOther)
})
}

@ -4,6 +4,8 @@ import (
"log/slog"
"net/http"
"runtime/debug"
"strconv"
"strings"
)
// serverError helper writes a log entry at Error level (including the request
@ -29,3 +31,32 @@ func serverError(w http.ResponseWriter, r *http.Request, err error) {
func clientError(w http.ResponseWriter, status int) {
http.Error(w, http.StatusText(status), status)
}
func getClientIP(r *http.Request) string {
// Check X-Forwarded-For header first (for proxied requests)
forwardedFor := r.Header.Get("X-Forwarded-For")
if forwardedFor != "" {
// Take the first IP in case of multiple proxies
return strings.Split(forwardedFor, ",")[0]
}
// Fall back to RemoteAddr
return strings.Split(r.RemoteAddr, ":")[0]
}
func logAuthFailure(logger *slog.Logger, r *http.Request, email string) {
logger.Info("authentication attempt failed",
slog.String("event_type", "authentication_failure"),
slog.String("username", email),
slog.String("ip_address", getClientIP(r)),
slog.String("user_agent", r.Header.Get("User-Agent")))
}
func logAuthSuccess(logger *slog.Logger, r *http.Request, email string, userId int) {
logger.Info("successful login",
slog.String("event_type", "authentication_success"),
slog.String("username", email),
slog.String("user_id", strconv.Itoa(userId)),
slog.String("ip_address", getClientIP(r)),
slog.String("user_agent", r.Header.Get("User-Agent")))
}

@ -35,7 +35,7 @@ func addRoutes(mux *http.ServeMux,
mux.Handle("POST /user/signup", sm.LoadAndSave(handleUserSignupPost(logger, tc, fd, sm, userService)))
mux.Handle("GET /user/login", sm.LoadAndSave(handleUserLoginGet(tc, sm)))
mux.Handle("POST /user/login", sm.LoadAndSave(handleUserLoginPost(logger, tc, sm, fd, userService)))
mux.Handle("POST /user/logout", sm.LoadAndSave(handleUserLogoutPost()))
mux.Handle("POST /user/logout", sm.LoadAndSave(handleUserLogoutPost(logger, sm)))
return mux
}

Loading…
Cancel
Save