refactored auth.go & tests
This commit is contained in:
@@ -2,9 +2,7 @@ package middlewares
|
||||
|
||||
import (
|
||||
"GoMembership/internal/config"
|
||||
"GoMembership/internal/models"
|
||||
"GoMembership/internal/utils"
|
||||
customerrors "GoMembership/pkg/errors"
|
||||
"GoMembership/pkg/logger"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -34,26 +32,43 @@ func verifyAndRenewToken(tokenString string) (string, uint, error) {
|
||||
return "", 0, fmt.Errorf("Authorization token is required")
|
||||
}
|
||||
token, claims, err := ExtractContentFrom(tokenString)
|
||||
if err != nil {
|
||||
|
||||
if err != nil && !errors.Is(err, jwt.ErrTokenExpired) {
|
||||
logger.Error.Printf("Couldn't parse JWT token String: %v", err)
|
||||
return "", 0, err
|
||||
}
|
||||
sessionID := (*claims)["session_id"].(string)
|
||||
userID := uint((*claims)["user_id"].(float64))
|
||||
roleID := int8((*claims)["role_id"].(float64))
|
||||
|
||||
if token.Valid {
|
||||
// token is valid, so we can return the old tokenString
|
||||
return tokenString, uint((*claims)["user_id"].(float64)), nil
|
||||
}
|
||||
|
||||
// Token is expired but valid
|
||||
sessionID, ok := (*claims)["session_id"].(string)
|
||||
if !ok || sessionID == "" {
|
||||
return "", 0, fmt.Errorf("invalid session ID")
|
||||
}
|
||||
id, ok := (*claims)["user_id"]
|
||||
if !ok {
|
||||
return "", 0, fmt.Errorf("missing user_id claim")
|
||||
}
|
||||
userID := uint(id.(float64))
|
||||
|
||||
id, ok = (*claims)["role_id"]
|
||||
if !ok {
|
||||
return "", 0, fmt.Errorf("missing role_id claim")
|
||||
}
|
||||
roleID := int8(id.(float64))
|
||||
|
||||
session, ok := sessions[sessionID]
|
||||
if !ok {
|
||||
logger.Error.Printf("session not found")
|
||||
return "", 0, fmt.Errorf("session not found")
|
||||
}
|
||||
|
||||
if userID != session.UserID {
|
||||
return "", 0, fmt.Errorf("Cookie has been altered, aborting..")
|
||||
}
|
||||
if token.Valid {
|
||||
// token is valid, so we can return the old tokenString
|
||||
return tokenString, session.UserID, customerrors.ErrValidToken
|
||||
}
|
||||
|
||||
if time.Now().After(sessions[sessionID].ExpiresAt) {
|
||||
delete(sessions, sessionID)
|
||||
@@ -64,8 +79,8 @@ func verifyAndRenewToken(tokenString string) (string, uint, error) {
|
||||
|
||||
logger.Error.Printf("Session still valid generating new token")
|
||||
// Session is still valid, generate a new token
|
||||
user := models.User{ID: userID, RoleID: roleID}
|
||||
newTokenString, err := GenerateToken(config.Auth.JWTSecret, &user, sessionID)
|
||||
user := map[string]interface{}{"user_id": userID, "role_id": roleID}
|
||||
newTokenString, err := GenerateToken(&config.Auth.JWTSecret, user, sessionID)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
@@ -89,11 +104,6 @@ func AuthMiddleware() gin.HandlerFunc {
|
||||
|
||||
newToken, userID, err := verifyAndRenewToken(tokenString)
|
||||
if err != nil {
|
||||
if err == customerrors.ErrValidToken {
|
||||
c.Set("user_id", uint(userID))
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
logger.Error.Printf("Token(%v) is invalid: %v\n", tokenString, err)
|
||||
c.JSON(http.StatusUnauthorized,
|
||||
gin.H{"errors": []gin.H{{
|
||||
@@ -104,24 +114,30 @@ func AuthMiddleware() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
utils.SetCookie(c, newToken)
|
||||
if newToken != tokenString {
|
||||
utils.SetCookie(c, newToken)
|
||||
}
|
||||
c.Set("user_id", uint(userID))
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateToken(jwtKey string, user *models.User, sessionID string) (string, error) {
|
||||
// GenerateToken generates a new JWT token with the given claims and session ID.
|
||||
// "user_id": user.ID, "role_id": user.RoleID
|
||||
func GenerateToken(jwtKey *string, claims map[string]interface{}, sessionID string) (string, error) {
|
||||
if sessionID == "" {
|
||||
sessionID = uuid.New().String()
|
||||
}
|
||||
token := jwt.NewWithClaims(jwtSigningMethod, jwt.MapClaims{
|
||||
"user_id": user.ID,
|
||||
"role_id": user.RoleID,
|
||||
"session_id": sessionID,
|
||||
"exp": time.Now().Add(time.Minute * 1).Unix(), // Token expires in 10 Minutes
|
||||
})
|
||||
UpdateSession(sessionID, user.ID)
|
||||
return token.SignedString([]byte(jwtKey))
|
||||
claims["session_id"] = sessionID
|
||||
claims["exp"] = time.Now().Add(time.Minute * 1).Unix() // Token expires in 10 Minutes
|
||||
token := jwt.NewWithClaims(jwtSigningMethod, jwt.MapClaims(claims))
|
||||
|
||||
userID, ok := claims["user_id"].(uint)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("invalid user_id in claims")
|
||||
}
|
||||
UpdateSession(sessionID, userID)
|
||||
return token.SignedString([]byte(*jwtKey))
|
||||
}
|
||||
|
||||
func ExtractContentFrom(tokenString string) (*jwt.Token, *jwt.MapClaims, error) {
|
||||
@@ -130,23 +146,33 @@ func ExtractContentFrom(tokenString string) (*jwt.Token, *jwt.MapClaims, error)
|
||||
return []byte(config.Auth.JWTSecret), nil
|
||||
})
|
||||
|
||||
if !errors.Is(err, jwt.ErrTokenExpired) && err != nil {
|
||||
logger.Error.Printf("Error during token(%v) parsing: %#v", tokenString, err)
|
||||
// Handle parsing errors (excluding expiration error)
|
||||
if err != nil && !errors.Is(err, jwt.ErrTokenExpired) {
|
||||
logger.Error.Printf("Error parsing token: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Token is expired, check if session is still valid
|
||||
claims, ok := token.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
logger.Error.Printf("Invalid Token Claims")
|
||||
return nil, nil, fmt.Errorf("invalid token claims")
|
||||
// Ensure token is not nil (e.g., malformed tokens)
|
||||
if token == nil {
|
||||
logger.Error.Print("Token is nil after parsing")
|
||||
return nil, nil, fmt.Errorf("invalid token")
|
||||
}
|
||||
|
||||
// Extract and validate claims
|
||||
claims, ok := token.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
logger.Error.Printf("invalid session_id in token")
|
||||
return nil, nil, fmt.Errorf("invalid session_id in token")
|
||||
logger.Error.Print("Invalid token claims structure")
|
||||
return nil, nil, fmt.Errorf("invalid token claims format")
|
||||
}
|
||||
return token, &claims, nil
|
||||
|
||||
// Validate required session_id claim
|
||||
if _, exists := claims["session_id"]; !exists {
|
||||
logger.Error.Print("Missing session_id in token claims")
|
||||
return nil, nil, fmt.Errorf("missing session_id claim")
|
||||
}
|
||||
|
||||
// Return token, claims, and original error (might be expiration)
|
||||
return token, &claims, err
|
||||
}
|
||||
|
||||
func UpdateSession(sessionID string, userID uint) {
|
||||
|
||||
Reference in New Issue
Block a user