first commit

This commit is contained in:
2025-09-12 12:38:11 +02:00
commit 0db2fd0314
46 changed files with 23221 additions and 0 deletions

158
backend/middleware/auth.go Normal file
View File

@@ -0,0 +1,158 @@
package middleware
import (
"net/http"
"project-dashboard/api/utils"
"project-dashboard/models"
"strings"
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
)
type Claims struct {
UserID uint `json:"user_id"`
Email string `json:"email"`
Role string `json:"role"`
jwt.StandardClaims
}
var jwtSecret = []byte("your-secret-key") // In production, use environment variable
// GenerateToken generates a JWT token for the user
func GenerateToken(user *models.User) (string, error) {
claims := Claims{
UserID: user.ID,
Email: user.Email,
Role: user.Role,
StandardClaims: jwt.StandardClaims{
ExpiresAt: 15000, // 24 hours
Issuer: "project-dashboard",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtSecret)
}
// AuthMiddleware validates JWT token
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
utils.ErrorResponse(c, http.StatusUnauthorized, "Authorization header required")
c.Abort()
return
}
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
if tokenString == authHeader {
utils.ErrorResponse(c, http.StatusUnauthorized, "Invalid authorization header format")
c.Abort()
return
}
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if err != nil || !token.Valid {
utils.ErrorResponse(c, http.StatusUnauthorized, "Invalid token")
c.Abort()
return
}
// Get user from database
var user models.User
if err := models.GetDB().First(&user, claims.UserID).Error; err != nil {
utils.ErrorResponse(c, http.StatusUnauthorized, "User not found")
c.Abort()
return
}
c.Set("user", &user)
c.Set("user_id", user.ID)
c.Next()
}
}
// AdminMiddleware ensures user has admin role
func AdminMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
user, exists := c.Get("user")
if !exists {
utils.ErrorResponse(c, http.StatusUnauthorized, "User not authenticated")
c.Abort()
return
}
userObj := user.(*models.User)
if !userObj.IsAdmin() {
utils.ErrorResponse(c, http.StatusForbidden, "Admin access required")
c.Abort()
return
}
c.Next()
}
}
// ManagerMiddleware ensures user has manager role or higher
func ManagerMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
user, exists := c.Get("user")
if !exists {
utils.ErrorResponse(c, http.StatusUnauthorized, "User not authenticated")
c.Abort()
return
}
userObj := user.(*models.User)
if !userObj.IsManager() {
utils.ErrorResponse(c, http.StatusForbidden, "Manager access required")
c.Abort()
return
}
c.Next()
}
}
// ProjectAccessMiddleware ensures user has access to the project
func ProjectAccessMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
user, exists := c.Get("user")
if !exists {
utils.ErrorResponse(c, http.StatusUnauthorized, "User not authenticated")
c.Abort()
return
}
userObj := user.(*models.User)
projectID := c.Param("project_id")
if projectID == "" {
utils.ErrorResponse(c, http.StatusBadRequest, "Project ID required")
c.Abort()
return
}
var project models.Project
if err := models.GetDB().Preload("Members").First(&project, projectID).Error; err != nil {
utils.ErrorResponse(c, http.StatusNotFound, "Project not found")
c.Abort()
return
}
// Check if user is owner or member
if !project.IsOwner(userObj.ID) && !project.HasMember(userObj.ID) {
utils.ErrorResponse(c, http.StatusForbidden, "Access denied to project")
c.Abort()
return
}
c.Set("project", &project)
c.Next()
}
}