171 lines
4.4 KiB
Go
171 lines
4.4 KiB
Go
package middleware
|
|
|
|
import (
|
|
"eslogad-be/internal/appcontext"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"eslogad-be/internal/constants"
|
|
"eslogad-be/internal/contract"
|
|
"eslogad-be/internal/logger"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type AuthMiddleware struct {
|
|
authService AuthValidateService
|
|
}
|
|
|
|
func NewAuthMiddleware(authService AuthValidateService) *AuthMiddleware {
|
|
return &AuthMiddleware{
|
|
authService: authService,
|
|
}
|
|
}
|
|
|
|
func (m *AuthMiddleware) RequireAuth() gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
token := m.extractTokenFromHeader(c)
|
|
if token == "" {
|
|
logger.FromContext(c.Request.Context()).Error("AuthMiddleware::RequireAuth -> Missing authorization token")
|
|
m.sendErrorResponse(c, "Authorization token is required", http.StatusUnauthorized)
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
userResponse, err := m.authService.ValidateToken(token)
|
|
if err != nil {
|
|
logger.FromContext(c.Request.Context()).WithError(err).Error("AuthMiddleware::RequireAuth -> Invalid token")
|
|
m.sendErrorResponse(c, "Invalid or expired token", http.StatusUnauthorized)
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
setKeyInContext(c, appcontext.UserIDKey, userResponse.ID.String())
|
|
|
|
if roles, perms, err := m.authService.ExtractAccess(token); err == nil {
|
|
c.Set("user_roles", roles)
|
|
c.Set("user_permissions", perms)
|
|
}
|
|
|
|
logger.FromContext(c.Request.Context()).Infof("AuthMiddleware::RequireAuth -> User authenticated: %s", userResponse.Email)
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func (m *AuthMiddleware) RequireRole(allowedRoles ...string) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
appCtx := appcontext.FromGinContext(c.Request.Context())
|
|
|
|
hasRequiredRole := false
|
|
for _, role := range allowedRoles {
|
|
if appCtx.UserRole == role {
|
|
hasRequiredRole = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !hasRequiredRole {
|
|
m.sendErrorResponse(c, "Insufficient permissions", http.StatusForbidden)
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func (m *AuthMiddleware) RequireAdminOrManager() gin.HandlerFunc {
|
|
return m.RequireRole("admin", "manager")
|
|
}
|
|
|
|
func (m *AuthMiddleware) RequireAdmin() gin.HandlerFunc {
|
|
return m.RequireRole("admin")
|
|
}
|
|
|
|
func (m *AuthMiddleware) RequireSuperAdmin() gin.HandlerFunc {
|
|
return m.RequireRole("superadmin")
|
|
}
|
|
|
|
func (m *AuthMiddleware) RequireActiveUser() gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
userResponse, exists := c.Get("user")
|
|
if !exists {
|
|
logger.FromContext(c.Request.Context()).Error("AuthMiddleware::RequireActiveUser -> User not authenticated")
|
|
m.sendErrorResponse(c, "Authentication required", http.StatusUnauthorized)
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
user, ok := userResponse.(*contract.UserResponse)
|
|
if !ok {
|
|
logger.FromContext(c.Request.Context()).Error("AuthMiddleware::RequireActiveUser -> Invalid user context")
|
|
m.sendErrorResponse(c, "Invalid user context", http.StatusInternalServerError)
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
if !user.IsActive {
|
|
logger.FromContext(c.Request.Context()).Errorf("AuthMiddleware::RequireActiveUser -> User account is deactivated: %s", user.Email)
|
|
m.sendErrorResponse(c, "User account is deactivated", http.StatusForbidden)
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
logger.FromContext(c.Request.Context()).Infof("AuthMiddleware::RequireActiveUser -> Active user check passed: %s", user.Email)
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func (m *AuthMiddleware) RequirePermissions(required ...string) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
if _, exists := c.Get("user_permissions"); !exists {
|
|
m.sendErrorResponse(c, "Authentication required", http.StatusUnauthorized)
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
permIface, _ := c.Get("user_permissions")
|
|
perms, _ := permIface.([]string)
|
|
userPerms := map[string]bool{}
|
|
for _, code := range perms {
|
|
userPerms[code] = true
|
|
}
|
|
|
|
for _, need := range required {
|
|
if !userPerms[need] {
|
|
m.sendErrorResponse(c, "Insufficient permissions", http.StatusForbidden)
|
|
c.Abort()
|
|
return
|
|
}
|
|
}
|
|
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func (m *AuthMiddleware) extractTokenFromHeader(c *gin.Context) string {
|
|
authHeader := c.GetHeader("Authorization")
|
|
if authHeader == "" {
|
|
return ""
|
|
}
|
|
|
|
parts := strings.Split(authHeader, " ")
|
|
if len(parts) != 2 || parts[0] != "Bearer" {
|
|
return ""
|
|
}
|
|
|
|
return parts[1]
|
|
}
|
|
|
|
func (m *AuthMiddleware) sendErrorResponse(c *gin.Context, message string, statusCode int) {
|
|
errorResponse := &contract.ErrorResponse{
|
|
Error: "auth_error",
|
|
Message: message,
|
|
Code: statusCode,
|
|
Details: map[string]interface{}{
|
|
"entity": constants.AuthHandlerEntity,
|
|
},
|
|
}
|
|
c.JSON(statusCode, errorResponse)
|
|
}
|