forgejo-tickets/internal/auth/session.go

91 lines
1.8 KiB
Go

package auth
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/mattnite/forgejo-tickets/internal/models"
)
const userContextKey = "user"
type requestContextKey string
const userRequestContextKey requestContextKey = "user"
func (s *Service) SessionMiddleware(c *gin.Context) {
session, err := s.store.Get(c.Request, sessionCookieName)
if err != nil || session.IsNew {
c.Next()
return
}
userIDStr, ok := session.Values["user_id"].(string)
if !ok {
c.Next()
return
}
userID, err := uuid.Parse(userIDStr)
if err != nil {
c.Next()
return
}
var user models.User
if err := s.db.First(&user, "id = ?", userID).Error; err != nil {
c.Next()
return
}
c.Set(userContextKey, &user)
// Also store on the request context so the template renderer can access it
c.Request = c.Request.WithContext(context.WithValue(c.Request.Context(), userRequestContextKey, &user))
c.Next()
}
func RequireAuth(c *gin.Context) {
if CurrentUser(c) == nil {
c.Redirect(http.StatusSeeOther, "/login")
c.Abort()
return
}
c.Next()
}
func RequireAdmin(c *gin.Context) {
user := CurrentUser(c)
if user == nil {
c.Redirect(http.StatusSeeOther, "/login")
c.Abort()
return
}
if !user.IsAdmin() {
c.Redirect(http.StatusSeeOther, "/")
c.Abort()
return
}
c.Next()
}
func CurrentUser(c *gin.Context) *models.User {
user, exists := c.Get(userContextKey)
if !exists {
return nil
}
u, ok := user.(*models.User)
if !ok {
return nil
}
return u
}
// CurrentUserFromRequest retrieves the current user from the request context.
// Used by the template renderer which receives *http.Request instead of *gin.Context.
func CurrentUserFromRequest(r *http.Request) *models.User {
user, _ := r.Context().Value(userRequestContextKey).(*models.User)
return user
}