refactor: Simplify AuthMiddleware;

refactor: Move token validation logic to AuthService;
refactor: Remove Redis cache checks from middleware;
fix: Improve error handling for token validation;
refactor: Update Refresh method to use new validation logic;
chore: Clean up unused imports and comments
This commit is contained in:
2025-07-15 22:37:41 +03:00
parent a582b75c82
commit e465da6854
3 changed files with 43 additions and 192 deletions

View File

@@ -509,96 +509,31 @@ func (a *authServiceImpl) Login(request models.LoginRequest) (*models.LoginRespo
func (a *authServiceImpl) Refresh(request models.RefreshRequest) (*models.RefreshResponse, error) {
var err error
sessionInfo, err := a.ValidateToken(request.RefreshToken, enums.JwtAccessTokenType); if err != nil {
return nil, err
}
token, err := jwt.ParseWithClaims(
request.RefreshToken,
&dto.UserClaims{},
func(token *jwt.Token) (any, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return []byte(config.GetConfig().JwtSecret), nil
accessToken, refreshToken, err := utils.GenerateTokens(
sessionInfo.Username,
sessionInfo.Session,
sessionInfo.Role,
); if err != nil {
a.log.Error(
"Failed to generate tokens for user during refresh",
zap.String("username", sessionInfo.Username),
zap.String("session", sessionInfo.Session),
zap.Error(err))
return nil, errs.ErrServerError
}
response := models.RefreshResponse{
Tokens: models.Tokens{
AccessToken: accessToken,
RefreshToken: refreshToken,
},
)
if err != nil {
if errors.Is(err, jwt.ErrTokenExpired) {
// AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Token expired"})
} else {
// c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
}
return nil, errs.ErrUnauthorized
}
if claims, ok := token.Claims.(*dto.UserClaims); ok && token.Valid {
if claims.Type != enums.JwtAccessTokenType {
// c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Not an access token"})
return nil, errs.ErrUnauthorized
}
ctx := context.TODO()
isTerminated, redisErr := a.redis.Get(ctx, fmt.Sprintf("session::%s::is_terminated", claims.Session)).Bool()
if redisErr != nil && redisErr != redis.Nil {
a.log.Error(
"Failed to lookup cache to check whether session is not terminated",
zap.Error(redisErr))
// c.AbortWithStatus(http.StatusInternalServerError)
return nil, errs.ErrServerError
}
// Cache if nil
if redisErr == redis.Nil {
db := database.NewDbHelper(a.dbctx)
session, err := db.Queries.GetSessionByGuid(db.CTX, claims.Session)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
a.log.Warn(
"Session does not exist or was deleted",
zap.String("session", claims.Session))
// c.AbortWithStatus(http.StatusUnauthorized)
return nil, errs.ErrUnauthorized
}
a.log.Error(
"Failed to lookup session in database",
zap.String("session", claims.Session),
zap.Error(err))
// c.AbortWithStatus(http.StatusInternalServerError)
return nil, errs.ErrServerError
}
if err := a.redis.Set(
ctx,
fmt.Sprintf("session::%s::is_terminated", claims.Session),
session.Terminated,
time.Duration(8 * time.Hour), // XXX: magic number
).Err(); err != nil {
a.log.Error(
"Failed to cache session's is_terminated state",
zap.String("session", claims.Session),
zap.Error(err))
// c.AbortWithStatus(http.StatusInternalServerError)
return nil, errs.ErrServerError
}
isTerminated = *session.Terminated
}
if isTerminated {
a.log.Warn(
"Attempt to access resource from a terminated session",
zap.String("session", claims.Session))
// c.AbortWithStatus(http.StatusUnauthorized)
return nil, errs.ErrUnauthorized
}
}
// TODO: generate some tokens
return nil, errs.ErrNotImplemented
return &response, nil
}
func (a *authServiceImpl) ValidateToken(jwtToken string, tokenType enums.JwtTokenType) (*dto.SessionInfo, error) {