mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-03 18:22:57 +00:00
104 lines
2.6 KiB
Go
104 lines
2.6 KiB
Go
package utils
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
)
|
|
|
|
// JWTClaims represents the JWT claims structure
|
|
type JWTClaims struct {
|
|
UserID uint `json:"user_id"`
|
|
Email string `json:"email"`
|
|
Role string `json:"role"`
|
|
jwt.RegisteredClaims
|
|
}
|
|
|
|
// GenerateJWT generates a new JWT token for the given user
|
|
func GenerateJWT(userID uint, email, role string) (string, error) {
|
|
// Respect configurable expiration via JWT_EXPIRATION_HOURS; default 24h
|
|
expHours := 24
|
|
if v := os.Getenv("JWT_EXPIRATION_HOURS"); v != "" {
|
|
if n, err := strconv.Atoi(v); err == nil && n > 0 && n <= 24*365 {
|
|
expHours = n
|
|
}
|
|
}
|
|
expirationTime := time.Now().Add(time.Duration(expHours) * time.Hour)
|
|
|
|
claims := &JWTClaims{
|
|
UserID: userID,
|
|
Email: email,
|
|
Role: role,
|
|
RegisteredClaims: jwt.RegisteredClaims{
|
|
ExpiresAt: jwt.NewNumericDate(expirationTime),
|
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
|
NotBefore: jwt.NewNumericDate(time.Now()),
|
|
Issuer: "fotbal-club",
|
|
},
|
|
}
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
tokenString, err := token.SignedString([]byte(GetJWTSecret()))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return tokenString, nil
|
|
}
|
|
|
|
// ParseJWT parses and validates a JWT token
|
|
func ParseJWT(tokenString string) (*JWTClaims, error) {
|
|
token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
|
|
return []byte(GetJWTSecret()), nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid {
|
|
return claims, nil
|
|
}
|
|
|
|
return nil, errors.New("invalid token")
|
|
}
|
|
|
|
// GetJWTSecret returns the JWT secret from environment variable or a default value
|
|
func GetJWTSecret() string {
|
|
secret := os.Getenv("JWT_SECRET")
|
|
if secret == "" {
|
|
return "default-secret-key-change-in-production"
|
|
}
|
|
return secret
|
|
}
|
|
|
|
// GetUserFromContext gets the authenticated user from Gin context
|
|
func GetUserFromContext(c *gin.Context) (*JWTClaims, error) {
|
|
// Preferred: claims set by auth middleware
|
|
if v, ok := c.Get("claims"); ok {
|
|
if cl, ok2 := v.(*JWTClaims); ok2 {
|
|
return cl, nil
|
|
}
|
|
}
|
|
// Fallback: parse Authorization header (Bearer <token>)
|
|
authHeader := c.GetHeader("Authorization")
|
|
if authHeader == "" {
|
|
return nil, errors.New("authorization header missing")
|
|
}
|
|
parts := strings.Split(authHeader, " ")
|
|
if len(parts) != 2 || parts[0] != "Bearer" {
|
|
return nil, errors.New("invalid authorization header format")
|
|
}
|
|
token := parts[1]
|
|
cl, err := ParseJWT(token)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return cl, nil
|
|
}
|